Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Force free() to return malloc memory back to OS

Seems like even after I free all the memory for a Linux process that was allocated by malloc(), memory is still reserved for the process and not returned to the OS.

Running valgrind massif tool by default reveals no leakages.

Running valgrind with --pages-as-heap=yes reveals this:

->13.77% (7,655,424B) 0x35FEEEB069: brk (brk.c:31)

->13.77% (7,655,424B) 0x35FEEEB113: sbrk (sbrk.c:53)

->13.77% (7,655,424B) 0x35FEE82717: __default_morecore (morecore.c:48)

->13.77% (7,655,424B) 0x35FEE7DCCB: _int_malloc (malloc.c:2455)

->13.77% (7,655,424B) 0x35FEE7F4F1: malloc (malloc.c:2862)

so even though memory was already freed by free(), it seems that malloc called brk/sbrk and did not return this to the OS.

how can I force free() to call sbrk() immediately and return all memory back to the OS ?

I am running on a very low end platform which every MB counts.

Thanks in advance.

like image 923
Itay Marom Avatar asked Jan 14 '15 14:01

Itay Marom


People also ask

Does free return memory to the OS?

When you free() or delete() this memory, it simply gets returned to the heap, not the OS. It's absolutely normal for that memory to not be returned to the operating system until your program exits, as you may request further memory later on.

Does malloc automatically free?

They are destroyed right at the exit from the function. This will happen automatically. You do not need to write anything for this. Heap allocations (result of a call to malloc ) are either released explicitly (with a call to free ) or they are cleaned up when the process ends.

How does free and malloc work?

In C, the library function malloc is used to allocate a block of memory on the heap. The program accesses this block of memory via a pointer that malloc returns. When the memory is no longer needed, the pointer is passed to free which deallocates the memory so that it can be used for other purposes.

How does malloc find free space?

malloc() keeps some data structure, let's say a list, of all the free chunks of space in the heap. When you call malloc, it looks through the list for a chunk that's big enough for you, returns a pointer to it, and records the fact that it's not free any more as well as how big it is.


2 Answers

With glibc malloc try to call malloc_trim function. It is not well documented and there were changes inside it at around 2007 (glibc 2.9) - https://stackoverflow.com/a/42281428.

Since 2007 this function will: Iterate over all malloc memory arenas (used in multithreaded applications) doing trim and fastbin consolidation; and release all aligned (4KB) pages fully freed.

https://sourceware.org/git/?p=glibc.git;a=commit;f=malloc/malloc.c;h=68631c8eb92ff38d9da1ae34f6aa048539b199cc

Ulrich Drepper Sun, 16 Dec 2007 22:53:08 +0000 (22:53 +0000)

  • malloc/malloc.c (public_mTRIm): Iterate over all arenas and call mTRIm for all of them.

(mTRIm): Additionally iterate over all free blocks and use madvise to free memory for all those blocks which contain at least one memory page.

https://sourceware.org/git/?p=glibc.git;a=blobdiff;f=malloc/malloc.c;h=c54c203cbf1f024e72493546221305b4fd5729b7;hp=1e716089a2b976d120c304ad75dd95c63737ad75;hb=68631c8eb92ff38d9da1ae34f6aa048539b199cc;hpb=52386be756e113f20502f181d780aecc38cbb66a

+  malloc_consolidate (av);
...
+  for (int i = 1; i < NBINS; ++i)
...
+        for (mchunkptr p = last (bin); p != bin; p = p->bk)
+         {
...
+               /* See whether the chunk contains at least one unused page.  */
+               char *paligned_mem = (char *) (((uintptr_t) p
+                                               + sizeof (struct malloc_chunk)
+                                               + psm1) & ~psm1);
...
+               /* This is the size we could potentially free.  */
+               size -= paligned_mem - (char *) p;
+
+               if (size > psm1)
+                 {
...
+                   madvise (paligned_mem, size & ~psm1, MADV_DONTNEED);

So, calling malloc_trim will release almost all freed memory back to the OS. Only pages containing still not freed data will be kept; OS may unmap or not unmap physical page when madvised with MADV_DONTNEED and linux usually does unmap. madvised pages are still count to VSIZE (total virtual memory size of the process), but usually help to reduce RSS (amount of physical memory used by process).

Alternatively, you can try to switch into alternative malloc library: tcmalloc (gperftools / google-perftools) or jemalloc (facebook), both of them have aggressive rules of returning freed memory back to OS (with madvise MADV_DONTNEED or even MADV_FREE).

like image 132
osgx Avatar answered Sep 30 '22 14:09

osgx


The only reliable and portable way to have the OS reclaim memory is to exit the process and restart it again, restoring any state you need to continue.

Of course, writing your own malloc/free implementation using brk/sbrk according to your needs is the other option.

like image 33
Jens Avatar answered Sep 30 '22 13:09

Jens