我正在使用带有mmap()
标志的MAP_ANONYMOUS
分配一些内存。由于问题的特性,我经常需要将一些数据写入大内存块的一个页面(例如,位于中间),并保持其他部分不变。所以,我不会在未使用的内存中占很大比例来物理分配。
在我看来,这样的mmap()
调用只是给了一个指向一些0填充虚拟页面的指针,但由于写入时复制和请求分页机制,没有一个页面(除了第一个可能)之外实际上在RAM中分配,直到第一次尝试写入内存为止。
问题是:有一刻我从MAP_FAILED
得到mmap()
(以前有很多成功的调用,分配查询较少),当试图分配比我的物理大的内存块时RAM大小。因此,似乎实际分配了更多的页面,即使没有对它们的写访问权。
我需要你的帮助人员提出两个问题,首先: 我对匿名内存分配的看法是否正确,以及(如果没有),是什么不准确?
第二个:
在匿名mmap()
完成后,我如何衡量实际分配的页数?我尝试过使用mincore()
,结果显示几乎所有页面都“驻留”在内存中(即物理分配?)。所以,似乎mincore()
结果是错误的,或者我完全陷入困境:(
UPD。
似乎@Art提到的内存过度使用确实会影响到这一点。但是当我尝试禁用它时(将/proc/sys/vm/overcommit_memory
设置为1
模式或使用带有mmap()
标记的MAP_NORESERVE
,我的计算机严重冻结,并且硬重置是唯一的有帮助的事情。
答案 0 :(得分:1)
"它很复杂。" (需要注意的是:我对Linux系统的VM系统有更多的经验,但多年来我从Linux中获得了一些细节)
一般来说,你的假设是正确的。许多操作系统实际上在mmap
上除了记录&#34之外没有多少操作;在V"处有对象Y的X页分配。访问这些页面会导致页面错误,从而导致实际分配。 Linux的某些(或可能是所有?)版本将预先归零的只读页面映射到此类分配(不确定它是否已更改或是否仍然完成),其余部分的处理方式与写入时复制相同(对我而言,感觉这是一个糟糕的主意,因为它应该产生更多的TLB刷新,用于读取零内存的可疑优化,这应该很少发生,但我想Linux人已经对它进行了基准测试并发现它很好。)
有一些警告。仅仅因为你没有使用RAM并不意味着你将被允许过度使用这么多内存。某些Linux发行版默认启用一个不允许过度使用或不允许超过X%过度使用的设置。 Centos / RedHat就是其中之一(这可能是十年前的事了,我今天不知道这个州)。这意味着,即使您只使用实际物理内存的5%,如果您创建了100 + X%RAM的匿名映射,mmap也会失败。它有一个sysctl,查找它。它类似于/proc/sys/vm/overcommit_memory
或overcommit_ratio
或两者,或者甚至更多。
然后你必须知道资源限制。检查ulimit
是否允许创建大的映射(ulimit -v),问题可能就是这么简单。另外(我不确定Linux如何在这里做,但你可以创建简单的测试程序来尝试它),数据大小的资源限制(ulimit -d)可以被视为你可以使用的潜在页面而不是实际的页面您目前使用(换句话说,资源限制中没有过度使用)。
然后让我们回到仅使用您使用的页面的错误。已有研究检测访问模式和预测未来的错误(以便mmap:ed文件可以预读),但我不知道它在Linux中的状态。感觉将它应用于匿名映射会很愚蠢,但你永远不知道,也许有人试图变得聪明。为确保在您使用的mmap:ed块上使用madvise(..., MADV_RANDOM)
。
最后mincore
。我在Linux上的经验是它的垃圾,上次我试过它它不适用于匿名映射(或者它是私有的吗?)。在您的情况下,它可以像报告匿名映射的只读拷贝写入归零页面被视为"在核心"中一样简单。