mmap/mprotect-只读的零页面是否算作承诺的内存?

8
我希望在进程中保留虚拟地址空间,用于存储先前使用但现在不再需要的内存。我感兴趣的情况是,主机内核为Linux,并配置为防止超额提交(通过详细记账所有已提交内存来实现)。
如果我只想防止应用程序不再使用的数据占用物理内存或被交换到磁盘上(无论哪种方式都浪费资源),我可以向内核发出“madvise”指令,表示这些数据不再需要,或者用新的零页覆盖它们。但这两种方法都不一定会减少计入已提交内存的内存量,这会阻止其他进程使用该内存。
如果我用新的零页替换这些页面,并将其标记为只读,那么我的意图是它们不计入已提交内存,并且我稍后可以使用“mprotect”将其设置为可写,如果将其设置为可写会超过已提交内存限制,则会失败。我的理解正确吗?这样做可行吗?

1
一个只读页面不应该被考虑在进程的提交费用中(我手头没有参考资料,所以这不是一个答案),Linux提供了MAP_NORESERVE标志,这应该给你更强的保证。但我必须问一下:为什么你觉得需要预留未使用的内存? - Anon
如果在程序不知情的情况下,由mmap(随机地)分配相同的虚拟地址,那么会发生糟糕的事情。:-)至于MAP_NORESERVE,我担心即使我稍后将页面设置为可写,也可能导致页面未被计数。我想我可以用新的零页面再次进行mmap覆盖它们。 - R.. GitHub STOP HELPING ICE
会发生什么不好的事情?为什么你的程序需要永远不重复使用之前使用过的地址空间?这似乎非常不寻常。 - Angus
这些页面是较大连续数据结构的一部分,目前未被使用。它们将在未来某个时候再次被使用,除非内核无法为它们提交空间,此时我将处理错误条件。如果虚拟地址被取消映射,则在此期间可能会有其他内容映射到那里。这有点简化了问题,但传达了基本观点。 - R.. GitHub STOP HELPING ICE
3
由于没有确切知识的回答,我认为你最好的选择是编写一个测试程序,用只读页面填充其虚拟地址空间,并观察它对交换空间的影响。 - Anon
确实。作为这个的变体,我可以禁用交换并制作一个测试程序,用数据填充物理内存大小的90%,然后在只读零页面中创建相同的虚拟大小,并最终尝试将它们写入保护,以查看是否/在哪里失败。 - R.. GitHub STOP HELPING ICE
2个回答

1

如果您没有使用页面(读取或写入它),它将不会提交到您的地址空间(仅保留)。

但是您的地址空间是有限的,因此您不能随心所欲地使用它。

例如,ElectricFence可能在分配大量内存时失败,因为插入了“nul页面/保护页面”(无访问权限的匿名内存)。请参阅以下线程:“mprotect() failed: Cannot allocate memory”: http://thread.gmane.org/gmane.comp.lib.glibc.user/538/focus=976052


3
它将会被计入虚拟大小,但不会计入常驻内存集(RSS)。 - Zan Lynx

1

在Linux上,假设overcommit没有被禁用,您可以使用MAP_NORESERVE标志来使用mmap,这将确保所涉及的页面在被访问之前不会被视为已分配的内存。如果overcommit已完全禁用,请参见下面有关多映射页面的内容。

请注意,Linux对零页面的行为在过去的某些内核版本中发生了变化;在某些版本中,仅读取页面就会导致其被分配。在其他情况下,需要进行写操作。请注意,保护标志不会直接导致分配;但是它们可以防止您意外触发分配。因此,为了获得最可靠的结果,您应该通过使用PROT_NONE进行mprotect以避免访问页面。

作为另一种更便携的选择,您可以在多个位置映射相同的页面。也就是说,创建并打开一个空的临时文件,取消链接它,ftruncate到一些合理的页面数,然后在文件的偏移量0处重复地mmap。这将绝对保证内存只计算一次,不会影响程序的内存使用情况。您甚至可以使用MAP_PRIVATE在写入页面时自动重新分配它。

使用这种技术,可能会比MAP_NORESERVE技术占用更多的内存(无论是内核跟踪数据还是临时文件本身的页面),因此,我建议在有条件的情况下使用MAP_NORESERVE。 如果您确实使用了这种技术,请尝试使要映射的区域合理大(如果在Linux上,请将其放置在/dev/shm中以避免实际磁盘I/O)。每个单独的mmap调用都将消耗一定数量的(不可交换)内核内存来跟踪它,因此最好将该计数保持在较低水平。


1
总体来说是有用的信息,但 MAP_NORESERVE 不是很有用。当完全禁用 overcommit 时,它会被忽略。 - R.. GitHub STOP HELPING ICE
你认为在你的方案中,将/dev/zero映射为临时文件会像临时文件一样有效吗? - Zan Lynx
@Zan,不是的。/dev/zero映射和普通的MAP_ANON映射一样,因此将像任何其他内存分配一样被计算。 - bdonlan

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接