views:

457

answers:

5

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

I have a long-living application with active memory allocation-deallocation.

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

Upd1: If I have application, which memory consumption can be very different in daytime and nighttime (e.g.), can I force any of malloc's to return freed memory to system? Without such return freed memory will be swapped out and in many times, but such memory contains only garbage.

+2  A: 

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.

As some people below have mentioned, there are special circumstances when malloc implementations will attempt to return memory to the OS. I wouldn't generally rely on this. Instead think about mmap()ing a new segment for your overnight processing and then unmap when you are done. Obviously you will need to do something about heap management, but allocation can be a very simple pool-style allocation (ie. free is a no-op) since you will release the entire memory segment at the end of your overnight processing job.
+3  A: 

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).

Alex Martelli
Can I use fork in multithreaded app? So I really CANT use fork.
osgx
@osgx: Yes you can can fork in a multithreaded application as long as you only use it to exec a new process. Well, actually "... the child process may only execute async-signal-safe operations until such time as one of the exec functions is called"
Zan Lynx
+2  A: 

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.

Andrew McGregor
Thanks! Can you name other allocators, which can return memory back to the system
osgx
Actually, it seems like glibc will as well, but the default threshold is for only allocations 128kB and larger to be made in this way. OpenBSD is mmap-backed for all allocations, and so free will almost always return memory. However, there is a big performance tradeoff; mmap-backed memory is much, much slower in many cases, and will induce a lot of page-faults to zero it, which may be even worse than the small amount of swap pressure it saves.
Andrew McGregor
@Andrew, yep, but the OpenBSD's motivation is security, not performance (as my answer mentions). Didn't know about `glibc`, will investigate, tx.
Alex Martelli
+1  A: 

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

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

    env TCMALLOC_RELEASE=100 ./my_pthread_soft

it is said in the documentation (http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html), "Reasonable rates are in the range [0,10]." , but 10 doesn't seem enough for me (i.e I see no change).

or :

  • find somewhere in your code where it would be interesting to release all the free-ed memory :

add in your file if it's C #include "google/malloc_extension_c.h" or c++ #include "google/malloc_extension.h" Then call MallocExtension_ReleaseFreeMemory();

The second solution is for me very effective, the first would be great but it isn't very successful, it is complicated to find the right number for example.

Laurent Debricon
Thanks, sounds rather interesting.
osgx
+1  A: 

The following analysis applies only to glibc (based on ptmalloc2 algorithm). There are certain options that seem helpful to return the freed memory back to the system:-

1) mallopt() function (defined in malloc.c) does provide an option to set the trim threshold value using one of the parameter option M_TRIM_THRESHOLD,this indicates the minimum amount of free memory (in bytes) allowed at the top of the data segment. If the amount falls below this threshold, glibc invokes brk( ) to give back memory to the kernel. The default value of TRIM_THRESHOLD in linux is set to 128K,setting a smaller value might save space.

The same behavior could be achieved by setting trim threshold value in the environment variable MALLOC_TRIM_THRESHOLD_ ,with no source changes absolutely.

However, preliminary test program runs using M_TRIM_THRESHOLD has shown that even though the memory allocated by malloc does return to the system,the remaining portion of the actual chunk of memory(the arena) initially requested via brk() tends to be retained.

2) It is possible to trim the memory arena and give any unused memory back to the system by calling malloc_trim(pad)(defined in malloc.c). This function resizes the data segment, leaving at least pad bytes at the end of it and failing if less than one page worth of bytes can be freed. Segment size is always a multiple of one page, which is 4,096 bytes on i386

The implementation for this modified behaviour of free using malloc_trim could be done using the malloc hook functionality. This would not require any source code changes to the core glibc library

3) using madvise system call inside the free implementation of glibc.

Please let me know your views on the above options.

Shashi