title: How can I force MacOS to release MADV_FREE'd pages?
body: <p>My program has a custom allocator which gets memory from the OS using <code>mmap(MAP_ANON | MAP_PRIVATE)</code>.  When it no longer needs memory, the allocator calls either <code>munmap</code> or <code>madvise(MADV_FREE)</code>.  <code>MADV_FREE</code> keeps the mapping around, but tells the OS that it can throw away the physical pages associated with the mapping.</p>
  
  <p>Calling <code>MADV_FREE</code> on pages you're going to need again eventually is much faster than calling <code>munmap</code> and later calling <code>mmap</code> again.</p>
  
  <p>This almost works perfectly for me.  The only problem is that, on MacOS, MADV_FREE is very lazy about getting rid of the pages I've asked it to free.  In fact, it only gets rid of them when there's memory pressure from another application.  Until it gets rid of the pages I've freed, MacOS reports that my program is still using that memory; in the Activity Monitor, its "Real Memory" column doesn't reflect the freed memory.</p>
  
  <p>This makes it difficult for me to measure how much memory my program is actually using.  (This difficulty in measuring RSS is keeping us from landing the custom allocator on 10.5.)</p>
  
  <p>I could allocate a whole bunch of memory to force the OS to free up these pages, but in addition to taking a long time, that could have other side-effects, such as causing parts of my program to be paged out to disk.</p>
  
  <p>On a lark, I tried the <code>purge</code> command, but that has no effect.</p>
  
  <p><strong>How can I force MacOS to clean out these MADV_FREE'd pages?  Or, how can I ask MacOS how many MADV_FREE'd pages my process has in memory?</strong></p>
  
  <p>Here's a test program, if it helps.  The Activity Monitor's "Real Memory" column shows 512MB after the program goes to sleep.  On my Linux box, top shows 256MB of RSS, as desired.</p>
  
  <pre><code>#include &lt;sys/mman.h&gt;
  #include &lt;stdio.h&gt;
  #include &lt;unistd.h&gt;
  
  #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 &lt; 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;
  }
  </code></pre>