2011-10-10 33 views
3

我的程序有一个自定义分配器,它使用mmap(MAP_ANON | MAP_PRIVATE)从操作系统获取内存。当不再需要内存时,分配器调用munmapmadvise(MADV_FREE)MADV_FREE保持映射,但告诉操作系统,它可以扔掉与映射关联的物理页面。如何强制MacOS发布MADV_FREE的网页?

在最后需要的页面上调用MADV_FREE最终会比调用munmap并且稍后再次调用mmap快得多。

这几乎适合我。唯一的问题是,在MacOS上,MADV_FREE对于摆脱我要求释放的页面非常懒惰。事实上,只有在有来自其他应用程序的内存压力时才会摆脱它们。在摆脱我释放的页面之前,MacOS报告说我的程序仍在使用该内存;在活动监视器中,其“实际内存”列不反映释放的内存。

这使我很难测量我的程序实际使用的内存量。 (这个测量RSS的难度让我们无法登陆10.5的自定义分配器。)

我可以分配一大堆内存来强制操作系统释放这些页面,但除了花费很长时间,可能会有其他副作用,例如导致我的程序的某些部分被分页到磁盘。

在云雀上,我尝试了purge命令,但是没有任何效果。

如何强制MacOS清除这些MADV_FREE的页面?或者,我怎么能问MacOS我的进程在内存中有多少个MADV_FREE的页面?

这是一个测试程序,如果有帮助的话。程序进入休眠状态后,Activity Monitor的“Real Memory”列显示512MB。根据需要,在我的Linux机器上,顶部显示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; 
} 

回答

0

我看了看,看起来,我不认为这是可能的。 :\

我们正在通过向分配程序添加代码来解决问题,该分配程序会在我们提出要求时显式解除MADV_FREE的页面。

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

注意就像你说的,是由madvise懒惰,而这可能是性能(以防万一有人不禁要使用性能,而不是测量)更好。

+0

我应该测量这个的性能影响,但我同意它可能会更慢。 但是,我希望找到某种方法来清除所有MADV_FREE的页面或测量它们的大小,而不是退回到另一种方法。 –

+1

这为什么会这样工作?调用mprotect会释放页面没有任何理由。 –

+0

我真的不知道为什么这会起作用,但如果您尝试测试代码,您会看到它的确存在(至少,它至少在一台计算机上,至少在一个版本的Mac OS X上) –