2010-12-01 47 views
8

我想在我的進程中保留以前使用但目前不需要的內存的虛擬地址空間。我對主機內核是Linux並且配置爲防止過度使用(通過詳細記錄所有已提交的內存)的情況感興趣。mmap/mprotect-readonly零頁是否計入已提交的內存?

如果我只是想阻止我的應用程序不再使用從佔用物理內存或交換到磁盤(浪費資源的任何方式)的數據,我可以madvise它不需要的內核或mmap新的零頁它的頂部。但是,這些方法都不一定會減少提交的內存數量,然後阻止使用其他進程。

如果我將頁面替換爲標記爲只讀的新頁面,該怎麼辦?我的意圖是,他們不計入承諾的內存,並進一步,我可以稍後使用mprotect使它們可寫,並且它將失敗,如果使它們可寫將超過承諾的內存限制。我的理解是否正確?這會工作嗎?

+1

一個只讀頁面不應該被考慮在一個進程的提交費用中(我手頭沒有參考,所以這不是一個答案),Linux提供了MAP_NORESERVE標誌,這應該會給你一個更強的保證。但我必須問:爲什麼你覺得需要預留未被使用的內存? – Anon 2010-12-01 21:56:30

+0

如果相同的虛擬地址被mmap(隨機)分配而沒有程序意識到它會發生壞事(tm)。 :-)對於`MAP_NORESERVE`,我擔心可能會讓頁面不再被計數,即使我稍後可以對其進行保護。我想我可以用新的零頁再次對他們進行「映射」。 – 2010-12-01 22:59:23

+0

會發生什麼壞事?爲什麼你的程序不需要重複以前使用的地址空間?這似乎很不尋常。 – Angus 2010-12-01 23:44:43

回答

1

如果您未使用該頁面(讀取或寫入該頁面),則該頁面不會被提交到您的地址空間(僅保留)。

但是你的地址空間有限,所以你不能隨心所欲地玩它。

例如參見ElectricFence,由於插入了「nul page/guard page」(無法訪問的匿名存儲器),可能會導致大量分配失敗。 看一看這些線程:「則mprotect()失敗:無法分配內存」: http://thread.gmane.org/gmane.comp.lib.glibc.user/538/focus=976052

1

在Linux上,假設過量使用沒有被禁用,則可以使用MAP_NORESERVE標誌mmap,這將確保該頁面在被訪問之前不會被記錄爲分配的內存。如果過度使用已完全禁用,請參閱下面關於多重映射頁面。

請注意,Linux的零頁行爲在過去有時會發生變化;對於某些內核版本,只需讀取頁面就會導致它被分配。與其他人一起寫作是必要的。請注意,保護標誌不會直接導致分配;但是它們可以防止您意外觸發分配。因此,對於最可靠的結果,您應該避免使用 PROT_NONE來訪問頁面。

作爲另一種更便攜的選項,您可以在多個位置映射相同的頁面。也就是說,創建並打開一個空的臨時文件,將其解除鏈接ftruncate一些合理數量的頁面,然後mmap重複在偏移0到文件中。這將絕對保證內存僅對您程序的內存使用情況計數一次。當您寫入頁面時,您甚至可以使用MAP_PRIVATE自動重新分配它。

但是,這可能比MAP_NORESERVE技術(內核跟蹤數據和臨時文件本身的頁面)有更高的內存使用率,因此,我建議在可用時使用MAP_NORESERVE。如果您確實使用了這種技術,請嘗試使映射的區域相當大(如果在Linux上,則將其放在/dev/shm中,以避免實際的磁盤IO)。每個調用將會消耗一定數量的(不可交換的)內核內存來跟蹤它,所以最好保持這一點。