看板 C_and_CPP 關於我們 聯絡資訊
10. 不要在 stack 設置過大的變數以避免堆疊溢位(stack overflow) 由於編譯器會自行決定 stack 的上限,某些預設是數 KB 或數十KB,當變數所需的空 間過大時,很容易造成 stack overflow,程式亦隨之當掉(segmentation fault)。 可能造成堆疊溢位的原因包括遞迴太多次(多為程式設計缺陷), 或是在 stack 設置過大的變數。 錯誤例子: int array[10000000]; // 在stack宣告過大陣列 std::array<int, 10000000> myarray; //在stack宣告過大std::array 正確例子: C: int *array = (int*) malloc( 10000000*sizeof(int) ); C++: std::vector<int> v; v.resize(10000000); 說明:建議將使用空間較大的變數用malloc/new配置在 heap 上,由於此時 stack 上只需配置一個 int* 的空間指到在heap的該變數,可避免 stack overflow。 使用 heap 時,雖然整個 process 可用的空間是有限的,但採用動態抓取 的方式,new 無法配置時會丟出 std::bad_alloc 例外,malloc 無法配置 時會回傳 null(註2),不會影響到正常使用下的程式功能 備註: 註1. 使用 heap 時,整個 process 可用的空間一樣是有限的,若是需要頻繁地 malloc / free 或 new / delete 較大的空間,需注意避免造成記憶體破碎 (memory fragmentation)。 註2. 由於Linux使用overcommit機制管理記憶體,malloc即使在記憶體不足時 仍然會回傳非NULL的address,同樣情形在Windows/Mac OS則會回傳NULL (感謝 LiloHuang 補充) 補充資料: - https://zh.wikipedia.org/wiki/%E5%A0%86%E7%96%8A%E6%BA%A2%E4%BD%8D - http://stackoverflow.com/questions/3770457/what-is-memory-fragmentation - http://library.softwareverify.com/memory-fragmentation-your-worst-nightmare/ overcommit跟malloc: - http://goo.gl/V9krbB - http://goo.gl/5tCLQc -- ※ 發信站: 批踢踢實業坊(ptt.cc), 來自: 223.136.189.53 ※ 文章網址: https://www.ptt.cc/bbs/C_and_CPP/M.1464012158.A.3DA.html
LiloHuang: Linux 上 malloc 回傳 non-NULL 不代表就是配置成功 05/23 22:20
LiloHuang: 要留意預設的 optimistic memory allocation strategy 05/23 22:21
kwpn: 若回傳non-NULL但是是失敗,要怎知道是失敗,有error code嗎 05/23 22:22
LiloHuang: 有興趣的可以看一下 Linux 文件 http://goo.gl/V9krbB 05/23 22:22
LiloHuang: 沒有辦法知道,除非關掉 overcommit 的機制 (預設為開) 05/23 22:23
wtchen: L大指的好像是realloc的情況?如果沒有辦法增加到想要 05/23 22:25
LiloHuang: 再來一篇延伸閱讀給有興趣的 http://goo.gl/5tCLQc 05/23 22:25
LiloHuang: 不單是 realloc,呼叫 malloc 幾乎都會回傳 non-NULL 05/23 22:25
LiloHuang: 因為採用 overcommit 的機制,建議把延伸閱讀看一下 05/23 22:26
LiloHuang: 看過不少人以為 non-NULL 就是可以讀寫,其實不一定... 05/23 22:28
wtchen: 這樣如果出現memory frag.不是很難debug嗎? 05/23 22:29
LiloHuang: overcommit 某種程度可以讓系統有效的利用實體記憶體 05/23 22:32
wtchen: kernel沒有限制user space使用memory的上限? 05/23 22:38
LiloHuang: 這是兩件事情,單一 process 是否達到上限,跟一堆 05/23 22:40
wtchen: 剛剛查了一下,Windows好像也有overcommit? 05/23 22:40
wtchen: 所以windows會有同樣的問題嗎? 05/23 22:41
LiloHuang: processes 配置了 1GB ,但是卻沒辦法正常存取是兩件事 05/23 22:41
LiloHuang: Windows / Mac OS X 在記憶體不夠用時,皆會回傳 NULL 05/23 22:42
※ 編輯: wtchen (223.136.189.53), 05/23/2016 23:02:14
tinlans: 標題殺人 被標題騙到很生氣地進來看 XD 05/25 12:02
抱歉造成誤解.... ※ 編輯: wtchen (220.128.143.228), 05/25/2016 12:53:42
hylkevin: linux會在需要實體記憶體時觸發swap或oom,所以頂多有 05/27 17:32
hylkevin: 效能問題,應該不至於會error。 05/27 17:32
LiloHuang: 不夠用就是會被 OOM killer 給砍掉... 不是無上限的 05/27 18:52
LiloHuang: #include <cstdlib> 05/27 18:58
LiloHuang: #include <cstring> 05/27 18:58
LiloHuang: int main() { 05/27 18:59
LiloHuang: const size_t CHUNK_SIZE = 1024*1024*1024; 05/27 18:59
LiloHuang: const size_t NUMBER_OF_CHUNK = 1024; 05/27 18:59
LiloHuang: void *chunks[NUMBER_OF_CHUNK]; 05/27 18:59
LiloHuang: // allocate without mapping 05/27 18:59
LiloHuang: for (size_t i=0; i<NUMBER_OF_CHUNK; i++) { 05/27 18:59
LiloHuang: chunks[i] = malloc(CHUNK_SIZE); 05/27 19:00
LiloHuang: } 05/27 19:00
LiloHuang: // use memset to map physical memory 05/27 19:00
LiloHuang: for (size_t i=0; i<NUMBER_OF_CHUNK; i++) { 05/27 19:00
LiloHuang: memset(chunks[i], 0x0, CHUNK_SIZE); 05/27 19:00
LiloHuang: } 05/27 19:00
LiloHuang: // reclaim allocated chunks 05/27 19:00
LiloHuang: for (size_t i=0; i<NUMBER_OF_CHUNK; i++) { 05/27 19:01
LiloHuang: free(chunks[i]); 05/27 19:01
LiloHuang: } 05/27 19:01
LiloHuang: return 0; 05/27 19:01
LiloHuang: } 05/27 19:01
LiloHuang: 有興趣的自己跑跑看上面,看會不會被 OOM killer 砍掉 05/27 19:02
LiloHuang: 順便檢查一下 malloc 的回傳值,是否都是 non-NULL 05/27 19:04
LiloHuang: 加個 if (!chunks[i]) throw std::bad_alloc(); 之類的 05/27 19:07
LiloHuang: 看到底是 OOM killer 砍掉還是 NULL dereference 掛掉 05/27 19:08
LiloHuang: 這三個迴圈一定要分開跑,寫成一個迴圈就不一定會被砍 05/27 19:09
wtchen: OOM不會選擇砍別的process嗎?如果在preempt RT kernel 05/27 19:16
wtchen: 的話加上mlockall就會砍別的process吧? 05/27 19:16
LiloHuang: 有評分機制,可參考 oom_kill.c https://goo.gl/vVqyeo 05/27 19:18
LiloHuang: 有可能別的 process 會被砍,假設它 oom_score 更高 05/27 19:20
LiloHuang: 只是上面的範例,通常會是被砍的那一個... :) 05/27 19:20
wtchen: 要寫的文章又多一篇 XD 05/27 20:32