2011-10-10 19 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上) –