mmap/mprotect-readonly 零页是否计入提交的内存?

发布于 2024-10-05 02:53:01 字数 359 浏览 5 评论 0原文

我想在进程中保留虚拟地址空间,用于以前使用过但目前不需要的内存。我对主机内核是 Linux 的情况感兴趣,它被配置为防止过度使用(它通过详细计算所有提交的内存来实现)。

如果我只是想防止我的应用程序不再使用的数据占用物理内存或交换到磁盘(无论哪种方式都浪费资源),我可以madvise内核认为它不再需要,或者mmap 在其之上添加新的零页。但这些方法都不一定会减少算作已提交的内存量,从而阻止其他进程使用这些内存量。

如果我用标记为只读的新零页替换这些页会怎样?我的意图是它们不计入提交的内存,而且我稍后可以使用 mprotect 使它们可写,并且如果使它们可写超出提交的内存限制,则会失败。我的理解正确吗?这行得通吗?

I want to keep virtual address space reserved in my process for memory that was previously used but is not presently needed. I'm interested in the situation where the host kernel is Linux and it's configured to prevent overcommit (which it does by detailed accounting for all committed memory).

If I just want to prevent the data that my application is no longer using from occupying physical memory or getting swapped to disk (wasting resources either way), I can madvise the kernel that it's unneeded, or mmap new zero pages over top of it. But neither of these approaches will necessarily reduce the amount of memory that counts as committed, which other processes are then prevented from using.

What if I replace the pages with fresh zero pages that are marked read-only? My intent is that they don't count towards committed memory, and further that I can later use mprotect to make them writable, and that it would fail if making them writable would go over the committed memory limit. Is my understanding correct? Will this work?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

怼怹恏 2024-10-12 02:53:01

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

但你的地址空间是有限的,所以你不能随心所欲地玩它。

例如,请参阅 ElectricFence,由于插入“空页/保护页”(无法访问的匿名内存),大量分配可能会失败。
看看这些线程:“mprotect() 失败:无法分配内存”:
http://thread.gmane.org/gmane.comp .lib.glibc.user/538/focus=976052

If you're not using the page (reading or writing to it), it won't be commited to your address space (only reserved).

But your address space is limited, so you can't play as you want/like with it.

See for example ElectricFence which may fail for large number of allocations, because of insertion of "nul page/guard page" (anonymous memory with no access).
Have a look at these thread : "mprotect() failed: Cannot allocate memory" :
http://thread.gmane.org/gmane.comp.lib.glibc.user/538/focus=976052

一抹淡然 2024-10-12 02:53:01

在 Linux 上,假设尚未禁用过度使用,您可以对 mmap 使用 MAP_NORESERVE 标志,这将确保有问题的页面不会被视为在之前分配的内存正在被访问。如果过度使用已完全禁用,请参阅下面有关多重映射页面的信息。

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

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

然而,这可能比 MAP_NORESERVE 技术(对于内核跟踪数据和临时文件本身的页面)具有更高的内存使用量,因此我建议使用 MAP_NORESERVE 相反,当可用时。如果您确实使用此技术,请尝试使映射的区域相当大(如果在 Linux 上,请将其放入 /dev/shm 中,以避免实际的磁盘 IO)。每个单独的 mmap 调用都会消耗一定量的(不可交换的)内核内存来跟踪它,因此最好保持该计数。

On Linux, assuming overcommit has not been disabled, you can use the MAP_NORESERVE flag to mmap, which will ensure that the page in question will not be accounted as allocated memory prior to being accessed. If overcommit has been completely disabled, see below about multiple-mapping pages.

Note that Linux's behavior for zero pages has changed at times in the past; with some kernel versions, simply reading the page would cause it to be allocated. With others, a write is necessary. Note that the protection flags do not cause allocation directly; however they can prevent you from accidentally triggering an allocation. Therefore, for most reliable results you should avoid accessing the page at all by mprotecting with PROT_NONE.

As another, more portable option, you can map the same page at multiple locations. That is, create and open an empty temp file, unlink it, ftruncate to some reasonable number of pages, then mmap repeatedly at offset 0 into the file. This will absolutely guarantee the memory only counts once against your program's memory usage. You can even use MAP_PRIVATE to auto-reallocate it when you write to the page.

This may have higher memory usage than the MAP_NORESERVE technique (both for kernel tracking data, and for the pages of the temp file itself), however, so I would recommend using MAP_NORESERVE instead when available. If you do use this technique, try to make the region being mapped reasonably large (and put it in /dev/shm if on Linux, to avoid actual disk IO). Each individual mmap call will consume a certain amount of (non-swappable) kernel memory to track it, so it's good to keep that count down.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文