Will malloc implementations return free-ed memory back to the system?

Viewed 22211

I have a long-living application with frequent memory allocation-deallocation. Will any malloc implementation return freed memory back to the system?

What is, in this respect, the behavior of:

  • ptmalloc 1, 2 (glibc default) or 3
  • dlmalloc
  • tcmalloc (google threaded malloc)
  • solaris 10-11 default malloc and mtmalloc
  • FreeBSD 8 default malloc (jemalloc)
  • Hoard malloc?

Update

If I have an application whose memory consumption can be very different in daytime and nighttime (e.g.), can I force any of malloc's to return freed memory to the system?

Without such return freed memory will be swapped out and in many times, but such memory contains only garbage.

8 Answers

Most implementations don't bother identifying those (relatively rare) cases where entire "blocks" (of whatever size suits the OS) have been freed and could be returned, but there are of course exceptions. For example, and I quote from the wikipedia page, in OpenBSD:

On a call to free, memory is released and unmapped from the process address space using munmap. This system is designed to improve security by taking advantage of the address space layout randomization and gap page features implemented as part of OpenBSD's mmap system call, and to detect use-after-free bugs—as a large memory allocation is completely unmapped after it is freed, further use causes a segmentation fault and termination of the program.

Most systems are not as security-focused as OpenBSD, though.

Knowing this, when I'm coding a long-running system that has a known-to-be-transitory requirement for a large amount of memory, I always try to fork the process: the parent then just waits for results from the child [[typically on a pipe]], the child does the computation (including memory allocation), returns the results [[on said pipe]], then terminates. This way, my long-running process won't be uselessly hogging memory during the long times between occasional "spikes" in its demand for memory. Other alternative strategies include switching to a custom memory allocator for such special requirements (C++ makes it reasonably easy, though languages with virtual machines underneath such as Java and Python typically don't).

I am dealing with the same problem as the OP. So far, it seems possible with tcmalloc. I found two solutions:

  1. compile your program with tcmalloc linked, then launch it as :

    env TCMALLOC_RELEASE=100 ./my_pthread_soft
    

    the documentation mentions that

    Reasonable rates are in the range [0,10].

    but 10 doesn't seem enough for me (i.e I see no change).

  2. find somewhere in your code where it would be interesting to release all the freed memory, and then add this code:

    #include "google/malloc_extension_c.h" // C include
    #include "google/malloc_extension.h"   // C++ include
    
    /* ... */
    
    MallocExtension_ReleaseFreeMemory();
    

The second solution has been very effective in my case; the first would be great but it isn't very successful, it is complicated to find the right number for example.

Of the ones you list, only Hoard will return memory to the system... but if it can actually do that will depend a lot on your program's allocation behaviour.

For all 'normal' mallocs, including the ones you've mentioned, memory is released to be reused by your process, but not back to the whole system. Releasing back to the whole system happens only when you process is finally terminated.

FreeBSD 12's malloc(3) uses jemalloc 5.1, which returns freed memory ("dirty pages") to the OS using madvise(...MADV_FREE).

Freed memory is only returned after a time delay controlled by opt.dirty_decay_ms and opt.muzzy_decay_ms; see the manual page and this issue on implementing decay-based unused dirty page purging for more details.

Earlier versions of FreeBSD shipped with older versions of jemalloc, which also returns freed memory, but uses a different algorithm to decide what to purge and when.

Related