【问题标题】:mmap(): resetting old memory to a zero'd non-resident statemmap():将旧内存重置为零非常驻状态
【发布时间】:2014-06-11 20:03:11
【问题描述】:

我正在编写一个内存分配例程,它目前运行顺利。我使用 4096 字节页面中的 mmap() 从操作系统获取内存。当我启动内存分配器时,我使用 mmap() 分配 1gig 的虚拟地址空间,然后在进行分配时,我根据分配算法的细节将其分成大块。

我觉得随意分配多达 1gig 的内存是安全的,因为我知道 mmap() 在我实际写入页面之前实际上不会将页面放入物理内存。

现在,使用我的分配器的程序可能会突然需要大量内存,在这种情况下,操作系统最终必须将整整 1gig 的页面放入物理 RAM。问题是程序可能会进入休眠期,释放大部分 1gig,然后只使用最少量的内存。然而,我在分配器的 MyFree() 函数中真正做的只是翻转一些簿记数据,这些数据将以前使用的 gig 标记为空闲,但我知道这不会导致操作系统从物理内存中删除这些页面。

我不能使用像 munmap() 这样的东西来解决这个问题,因为分配算法的本质是它需要一个连续的内存区域,其中没有任何漏洞。基本上我需要一种方法来告诉操作系统“听着,您可以将这些页面从物理内存中取出并将它们清除为 0,但是当我再次需要它们时请即时重新映射它们,就好像它们是新的 mmap()'d "

最好的方法是什么?

实际上,在写完这一切之后,我才意识到我可以先执行一个 munmap(),然后立即执行一个新的 mmap()。那是正确的方法吗?我觉得可能有一些更有效的方法可以做到这一点。

【问题讨论】:

  • 虚拟内存自动将未使用的内存从物理内存移到交换空间。你不需要做任何事情。

标签: linux macos memory-management posix mmap


【解决方案1】:

您正在寻找madvise(addr, length, MADV_DONTNEED)。来自the manpage

MADV_DONTNEED:不要指望在不久的将来访问。 (目前,应用程序在给定的范围内完成,因此内核可以释放与其关联的资源。)此范围内的页面的后续访问将成功,但将导致从底层映射的内存内容重新加载文件(参见 mmap(2))或零填充按需页面,用于没有基础文件的映射。

请特别注意有关后续访问将如何成功但恢复为按需零填充的语言(对于没有基础文件的映射)。

munmap 后面紧跟另一个 mmap 的大声思考的替代方案也可以工作,但存在内核端效率低下的风险,因为它不再跟踪单个连续区域的分配;如果有很多这样的 unmap-and-remap 事件,内核端的数据结构可能会变得非常臃肿。

顺便说一句,对于这种分配器,使用MAP_NORESERVE 进行初始分配非常重要,然后在分配时触摸每个页面,并捕获任何生成的SIGSEGV 并导致分配失败。 (并且您需要记录您的分配器为SIGSEGV 安装了一个处理程序。)如果您不这样做,您的应用程序将无法在禁用内存过量使用的系统上运行。有关详细信息,请参阅 mmap 联机帮助页。

【讨论】:

  • 如何恢复MADV_DONTNEED 的效果?只是写信给它?
  • 你不能撤消这个效果,但是随后对页面的读取或写入会结束这个效果:页面会被重新分配并且会被内存管理器正常处理。
猜你喜欢
  • 2020-03-02
  • 1970-01-01
  • 2021-12-13
  • 2011-03-15
  • 2023-03-09
  • 2010-09-20
  • 2019-08-06
  • 2013-09-08
  • 1970-01-01
相关资源
最近更新 更多