2010-08-02 75 views
4

當我運行下面的代碼,它慢慢地吃了我的記憶,甚至開始使用交換:NSMutableData如何分配內存?

long long length = 1024ull * 1024ull * 1024ull * 2ull; // 2 GB 

db = [NSMutableData dataWithLength:length]; 

char *array = [db mutableBytes]; 

for(long long i = 0; i < length - 1; i++) { 
     array[i] = i % 256; 
} 

如果我沒有對循環中沒有內存使用在所有運行:

long long length = 1024ull * 1024ull * 1024ull * 2ull; 
db = [NSMutableData dataWithLength:length]; 
char *array = [db mutableBytes]; 
/* for(long long i = 0; i < length - 1; i++) { 
     array[i] = i % 256; 
} */ 

我只能得出結論,NSMutableData只是「保留」內存,當它被訪問時,它真的「分配」它。它是如何完成的?

這是通過硬件(CPU)完成的嗎?

有沒有辦法讓NSMutableData在其「保留」內存中捕獲內存寫入,然後才執行「分配」?

這是否也意味着致電[NSMutableData dataWithLength:length]永遠不會失敗?它可以使用交換分配任何大小的內存來獲得它,如果需要?

如果它可以失敗將我的db變量爲空?

在蘋果的「NSMutableData類參考」中,我只看到了關於這些主題的模糊句子。

回答

6

這不是一個NSMutableData問題,而是一個內核/操作系統問題。如果進程請求(大)內存塊,內核通常會說「沒關係,在這裏你去」。但只有在實際使用它時,才真正(「物理上」)分配。這是可以的,因爲如果你的程序以一個2 GB的malloc開頭(就像你在這裏做的那樣),否則它會立即推出其他程序進行交換,而在實踐中,你通常不會使用2 GB。

訪問物理內存中實際不存在的內存頁時,內核將從CPU獲取信號。如果頁面應該在那裏(因爲它在你的2 GB大塊內),它將被放置(可能來自交換),你甚至不會注意到。如果頁面不在那裏(因爲地址未在虛擬內存中分配),則會出現分段錯誤(SIGSEGV或EXC_BAD_ACCESS類型的錯誤)。

其中一個相關主題是「overcommit(ment)」,其中內核承諾的內存比實際可用的多。如果所有進程都使用其承諾的內存,它可能會導致嚴重的問題。這取決於操作系統。

因特網上有很多頁面可以更好地解釋這個問題,我只是想給你一個簡短的介紹,所以你有條款放在谷歌。

編輯只是測試,Linux會輕易答應我4 TB的內存,而 - 我向你保證 - 竟然沒有1 TB總磁盤存儲在該機器。你可以想象,如果不加以關注,在構建關鍵任務系統時會造成一些麻煩。

+1

可以通過設置'overcommit_memory'和'overcommit_ratio'來改變Linux overcommit行爲。特別是,將'overcommit_memory'設置爲2意味着它只會提交物理內存的交換空間+ overcommit_ratio%。 – 2010-08-02 12:13:00

+0

另見[overcommit-accounting documentation](http://www.mjmwired.net/kernel/Documentation/vm/overcommit-accounting)。 – 2010-08-02 12:20:17

+0

關於linux的一個有趣的事情是'mmap()'(malloc在表面下面執行)需要一個標誌'MAP_NORESERVE',它允許超負荷的行爲。但是,如果您 - 像malloc() - 不指定此標誌,它仍然過量使用。 – mvds 2010-08-02 12:35:14