malloc申請大內存報錯分析

每個進程會有4G的虛擬地址空間, malloc得到的的地址都是虛擬地址, 並且當malloc的時候, 操作系統並不會將實際的內存分配給進程的, 所以malloc只會佔用進程自身的虛擬地址空間。
我以前也做過申請內存的測試,並且寫了一個短文:

操作系統: Redhat Linux AS5 32bit
服務器內存: 4G
服務器類型: I32

最近寫搜索引擎, 因爲創建索引需要大量的內存, 所以對Linux下的大內存申請進行了一些測試.

(1)char * p = (char *)malloc( 2G字節 );
=>申請失敗.
(2)char * p = (char *)malloc( 1.9G字節 );
=>申請成功
(3)連續的申請10個300M的內存空間
for ( i=0; i<10; i++ )
p = (char*)malloc(300M字節)
=>前9次成功, 最後1次申請失敗
(4)先申請1.9G, 再申請900M
p = (char *)malloc( 1.9G字節 );
p = (char *)malloc( 900M字節 );
=>兩次申請都成功.

我的理解如下:
對於在普通默認的2.6.*的linux內核!
32位的機器裏, 一個進程的內存地址空間範圍是0-3G共4個G, 其中最後一個G是內核態的地址空間, 所以給用戶態的內存地址空間只留下了前3個G. 那麼這樣, malloc能夠申請到3G以內的內存纔對, 但是結果並非如此.在(1)中我們申請2G的內存都沒有申請到, 這是什麼原因呢?先讓我們看一看實際上進程的4G內存空間都放着或被map着什麼:

第0G和第1G:用戶態地址空間
第2G:庫函數映射等
第3G:內核態內存空間

用戶態地址空間中還包含了進程代碼本身佔用的地址空間, 棧的空間等等.
第2G中, 庫函數映射等只佔用了很少的一部分空間,還有很多的空閒空間.

現在讓我們解釋這4個問題:
第(1)個問題, 由上圖可以看出, 沒有連續的2G的內存, 所以申請2G的連續內存是肯定失敗的.
第(2), 申請1.9G的空間是成功的, 這是因爲前兩個G可能會有1.9G的連續空間.
第(3), 申請了300M*9 = 2.7G是成功的, 是的, 前3G中有可能空間着2.7G的空間, 前兩個G中空閒的加上第3個G中空閒的部分. 但是如果一次申請2.7G是不行的, 因爲沒有連續的2.7G的地址空間. 最後一個300M沒有申請成功的原因是, 申請的空間大小不能超過3G的用戶態地址空間.
第(4), 比較有意思, 顯然那個1.9G是在第1-2G這個地址空間中申請成功的, 後900M是第3個G這片地址空間中申請成功的. 我們一共申請到了2.8G的"內存", 卻也不是連續的

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章