2010-12-01 30 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)。每个调用将会消耗一定数量的(不可交换的)内核内存来跟踪它,所以最好保持这一点。