1. 程式人生 > >malloc申請大記憶體報錯分析

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的"記憶體", 卻也不是連續的