如何强制MacOS释放已使用MADV_FREE释放的页面?

7
我的程序有一个自定义分配器,它使用 mmap(MAP_ANON | MAP_PRIVATE) 从操作系统获取内存。当不再需要内存时,分配器会调用 munmapmadvise(MADV_FREE)MADV_FREE 会保留映射,但告诉操作系统可以丢弃与映射相关联的物理页面。
在以后需要这些页面时调用 MADV_FREE 比先调用 munmap 再调用 mmap 更快。
这对我来说几乎完美地解决了问题。唯一的问题是,在 MacOS 上,MADV_FREE 很慢地清除了我要求它释放的页面。实际上,只有在另一个应用程序有内存压力时才会清除它们。在清除我释放的页面之前,MacOS 报告我的程序仍在使用该内存;在 Activity Monitor 中,其“实际内存”列不反映已释放的内存。
这使我难以测量我的程序实际使用了多少内存。(无法测量 RSS 正是阻止我们在 10.5 上使用自定义分配器的原因。)
我可以分配大量内存来强制操作系统释放这些页面,但除了需要很长时间外,这可能会产生其他副作用,例如导致我的程序的某些部分被分页到磁盘上。
我试过了 purge 命令,但没有效果。 我如何强制 MacOS 清除这些 MADV_FREE 的页面?或者,我如何询问 MacOS 我的进程中有多少 MADV_FREE 的页面在内存中? 如果有帮助,这是一个测试程序。程序休眠后,Activity Monitor 的“实际内存”列显示为 512MB。在我的 Linux 系统上,top 显示 256MB 的 RSS,正如所期望的那样。
#include <sys/mman.h>
#include <stdio.h>
#include <unistd.h>

#define SIZE (512 * 1024 * 1024)

// We use MADV_FREE on Mac and MADV_DONTNEED on Linux.
#ifndef MADV_FREE
#define MADV_FREE MADV_DONTNEED
#endif

int main()
{
  char *x = mmap(0, SIZE, PROT_READ | PROT_WRITE, MAP_ANON | MAP_PRIVATE, -1, 0);

  // Touch each page we mmap'ed so it gets a physical page.
  int i;
  for (i = 0; i < SIZE; i += 1024) {
    x[i] = i;
  }

  madvise(x, SIZE / 2, MADV_FREE);

  fprintf(stderr, "Sleeping.  Now check my RSS.  Hopefully it's %dMB.\n", SIZE / (2 * 1024 * 1024));
  sleep(1024);
  return 0;
}
3个回答

4
mprotect(addr, length, PROT_NONE);
mprotect(addr, length, PROT_READ | PROT_WRITE);

正如您所说,madvise更懒惰,这对性能可能更好(以防有人因性能而使用此选项,而不是用于测量)。


我应该测量这个的性能影响,但我同意它可能会更慢。但是为了明确起见,我希望找到一种清除所有MADV_FREE页面或测量其大小的方法,而不是退回到另一种方法。 - Justin L.
1
为什么会起作用?调用mprotect没有释放页面的任何理由。 - Per Johansson
我真的不知道这为什么有效,但如果您尝试测试代码,您会发现它确实有效(至少在至少一个 Mac OS X 版本上的至少一台计算机上)。 - Chris Jefferson

1

在 macOS 上使用 MADV_FREE_REUSABLE。根据苹果的 magazine_malloc 实现:

在 OS X 上,我们使用 MADV_FREE_REUSABLE,这会向内核发出信号,要求将给定页面从我们的进程内存统计中删除。但是,在将该内存返回使用之前,我们必须发出已被重用的信号。

https://opensource.apple.com/source/libmalloc/libmalloc-53.1.1/src/magazine_malloc.c.auto.html

例如,Chromium也使用它:
MADV_FREE_REUSABLE类似于MADV_FREE,但还标记具有可重用位的页面,这允许Activity Monitor和memory-infra正确跟踪页面。

https://github.com/chromium/chromium/blob/master/base/memory/discardable_shared_memory.cc#L377


0

我已经找了很久,但我认为这是不可能的。 :\

我们通过向分配器添加代码来解决问题,当我们要求它时,它会明确地取消分配MADV_FREE的页面。


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接