2016-12-14 56 views
1

我試圖從"Expert C Programming"做練習,其中的重點是看看一個程序可以分配多少內存。它取決於malloc當它不能再分配時返回NULLmalloc內核恐慌,而不是返回NULL

#include <stdio.h> 
#include <stdlib.h> 

int main() { 
    int totalMB = 0; 
    int oneMeg = 1<<20; 
    while (malloc(oneMeg)) { 
     ++totalMB; 
    } 
    printf("Allocated %d Mb total \n", totalMB); 
    return 0; 
} 

不是打印總數,而是在我的16GB Macbook Pro上分配〜8GB後出現內核恐慌。

內核崩潰日誌:

Anonymous UUID:  0B87CC9D-2495-4639-EA18-6F1F8696029F 

Tue Dec 13 23:09:12 2016 

*** Panic Report *** 
panic(cpu 0 caller 0xffffff800c51f5a4): "zalloc: zone map exhausted while allocating from zone VM map entries, likely due to memory leak in zone VM map entries (6178859600 total bytes, 77235745 elements allocated)"@/Library/Caches/com.apple.xbs/Sources/xnu/xnu-3248.50.21/osfmk/kern/zalloc.c:2628 
Backtrace (CPU 0), Frame : Return Address 
0xffffff91f89bb960 : 0xffffff800c4dab12 
0xffffff91f89bb9e0 : 0xffffff800c51f5a4 
0xffffff91f89bbb10 : 0xffffff800c5614e0 
0xffffff91f89bbb30 : 0xffffff800c5550e2 
0xffffff91f89bbba0 : 0xffffff800c554960 
0xffffff91f89bbd90 : 0xffffff800c55f493 
0xffffff91f89bbea0 : 0xffffff800c4d17cb 
0xffffff91f89bbf10 : 0xffffff800c5b8dca 
0xffffff91f89bbfb0 : 0xffffff800c5ecc86 

BSD process name corresponding to current thread: a.out 

Mac OS version: 
15F34 

我明白,這可以很容易地通過「?它傷害時,你這樣做,那麼不這樣做,」醫生的陳詞濫調是固定的,但我想知道爲什麼malloc沒有按預期工作。

OS X 10.11.5

+0

查找「懶惰分配」,這是操作系統的「功能」 –

回答

2

爲了明確回答這個問題,你可以看看源代碼,你會發現這裏:

zalloc.c source in XNU

在該源文件中找到函數zalloc_internal()。這是導致內核恐慌的函數。

在函數中你會發現一個「for(;;){」循環,它基本上試圖分配你在指定區域中請求的內存。如果沒有足夠的空間,它立即再次嘗試。如果失敗,它會執行zone_gc()(垃圾回收)來嘗試回收內存。如果這也失敗了,它只會導致內核恐慌 - 有效地停止計算機。

如果您想了解zalloc.c如何工作,請查找基於區域的內存分配器。

您的程序正在使內核空間不足,稱爲「VM映射條目」,這是在引導時分配的預定義區域。如果您一次分配1 MB以上的內存,您可能會從程序中獲得您期望的結果,而不會造成內核恐慌。

從本質上說,內核分配幾千兆字節的內存並不是一個真正的問題。但是,分配數千個總計達到千兆字節的較小分配要困難得多。

+0

更改分配的內存量不會導致程序成功運行,但它確實使內核不會出現混亂。 – valbaca

+0

取決於你的意思是「成功運行」。該程序不是一個真正的程序,而是一個教學示例,其中malloc函數在某些時候意味着失敗。 – jksoegaard

+0

「運行成功意味着:分配的內存可以通過while循環分配儘可能多的內存,當它嘗試分配第N + 1個MB時,malloc應該返回null,退出while循環,然後它應該printf並退出 – valbaca