我的程序有一個自定義分配器,它使用mmap(MAP_ANON | MAP_PRIVATE)
從操作系統獲取內存。當不再需要內存時,分配器調用munmap
或madvise(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;
}
我應該測量這個的性能影響,但我同意它可能會更慢。 但是,我希望找到某種方法來清除所有MADV_FREE的頁面或測量它們的大小,而不是退回到另一種方法。 –
這爲什麼會這樣工作?調用mprotect會釋放頁面沒有任何理由。 –
我真的不知道爲什麼這會起作用,但如果您嘗試測試代碼,您會看到它的確存在(至少,它至少在一臺計算機上,至少在一個版本的Mac OS X上) –