使用匿名mmap()检查实际分配的页数

时间:2018-04-05 11:06:12

标签: c++ c linux memory mmap

我正在使用带有mmap()标志的MAP_ANONYMOUS分配一些内存。由于问题的特性,我经常需要将一些数据写入大内存块的一个页面(例如,位于中间),并保持其他部分不变。所以,我不会在未使用的内存中占很大比例来物理分配。

在我看来,这样的mmap()调用只是给了一个指向一些0填充虚拟页面的指针,但由于写入时复制和请求分页机制,没有一个页面(除了第一个可能)之外实际上在RAM中分配,直到第一次尝试写入内存为止。

问题是:有一刻我从MAP_FAILED得到mmap()(以前有很多成功的调用,分配查询较少),当试图分配比我的物理大的内存块时RAM大小。因此,似乎实际分配了更多的页面,即使没有对它们的写访问权。

我需要你的帮助人员提出两个问题,首先: 我对匿名内存分配的看法是否正确,以及(如果没有),是什么不准确?

第二个: 在匿名mmap()完成后,我如何衡量实际分配的页数?我尝试过使用mincore(),结果显示几乎所有页面都“驻留”在内存中(即物理分配?)。所以,似乎mincore()结果是错误的,或者我完全陷入困境:(

UPD。 似乎@Art提到的内存过度使用确实会影响到这一点。但是当我尝试禁用它时(将/proc/sys/vm/overcommit_memory设置为1模式或使用带有mmap()标记的MAP_NORESERVE,我的计算机严重冻结,并且硬重置是唯一的有帮助的事情。

1 个答案:

答案 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_memoryovercommit_ratio或两者,或者甚至更多。

然后你必须知道资源限制。检查ulimit是否允许创建大的映射(ulimit -v),问题可能就是这么简单。另外(我不确定Linux如何在这里做,但你可以创建简单的测试程序来尝试它),数据大小的资源限制(ulimit -d)可以被视为你可以使用的潜在页面而不是实际的页面您目前使用(换句话说,资源限制中没有过度使用)。

然后让我们回到仅使用您使用的页面的错误。已有研究检测访问模式和预测未来的错误(以便mmap:ed文件可以预读),但我不知道它在Linux中的状态。感觉将它应用于匿名映射会很愚蠢,但你永远不知道,也许有人试图变得聪明。为确保在您使用的mmap:ed块上使用madvise(..., MADV_RANDOM)

最后mincore。我在Linux上的经验是它的垃圾,上次我试过它它不适用于匿名映射(或者它是私有的吗?)。在您的情况下,它可以像报告匿名映射的只读拷贝写入归零页面被视为"在核心"中一样简单。