我希望在我的进程中为以前使用但目前不需要的内存保留虚拟地址空间。我对主机内核是Linux的情况感兴趣,并且它被配置为防止过度使用(通过详细计算所有已提交的内存来实现)。
如果我只是想阻止我的应用程序不再使用的数据占用物理内存或交换到磁盘(以任何方式浪费资源),我可以madvise
不需要的内核,或{{ 1}}新的零页面。但是这些方法都不一定会减少计入提交的内存量,然后阻止其他进程使用。
如果我将页面替换为标记为只读的新零页怎么办?我的意图是它们不计入已提交的内存,而且我以后可以使用mmap
使它们可写,并且如果使它们可写将失败将超过提交的内存限制。我的理解是否正确?这有用吗?
答案 0 :(得分:1)
如果您没有使用该页面(读取或写入),它将不会被提交到您的地址空间(仅保留)。
但是你的地址空间有限,所以你无法按照自己的喜好玩它。
参见例如ElectricFence,由于插入了“nul page / guard page”(没有访问权限的匿名内存),因此大量分配可能会失败。 看看这些线程:“mprotect()失败:无法分配内存”: http://thread.gmane.org/gmane.comp.lib.glibc.user/538/focus=976052
答案 1 :(得分:1)
在Linux上,假设尚未禁用过度使用,您可以使用MAP_NORESERVE
标志mmap
,这将确保在访问之前,相关页面不会被视为已分配的内存。如果已完全禁用过度使用,请参阅下面有关多映射页面的信息。
请注意,Linux过去零页的行为有时会发生变化;对于某些内核版本,只需读取页面就会导致它被分配。与其他人一起,写作是必要的。请注意,保护标志不会直接导致分配;但是它们可以防止您意外触发分配。因此,为了获得最可靠的结果,您应该mprotect
PROT_NONE
来避免访问该页面。
另外,更便携的选项,您可以在多个位置映射同一页。也就是说,创建并打开一个空的临时文件,将其取消链接ftruncate
到一些合理数量的页面,然后在偏移0处重复mmap
到文件中。这绝对可以保证内存仅对您程序的内存使用量进行一次计数。您甚至可以在写入页面时使用MAP_PRIVATE
自动重新分配它。
这可能比MAP_NORESERVE
技术(内核跟踪数据和临时文件本身的页面)具有更高的内存使用率,但是,我建议在可用时使用MAP_NORESERVE
。如果您确实使用了这种技术,请尝试使区域映射得相当大(如果在Linux上,则将其放在/dev/shm
中,以避免实际的磁盘IO)。每个单独的mmap
调用都会消耗一定量的(不可交换的)内核内存来跟踪它,因此最好保持这个数量。