Does free() unmap the memory of a process?
The C-library function free()
can, but does not have to, return memory to the kernel.
Some implementations of malloc()
move the boundary between "heap" and otherwise unused address space (the "system break") via the sbrk()
system call, then dole out smaller pieces of those large allocations. Without getting every smaller piece de-allocated, free()
can't really return the memory to the OS.
That same reason applies to malloc()
implementations that don't use sbrk(2)
, but maybe use mmap("/dev/zero")
or something.. I can't find a reference, but I seem to remember that one or another of the BSD's used mmap()
that way to get pages of memory. Nevertheless, free()
can't return a page to the operating system unless every sub-allocation is deallocated by the program.
Some malloc()
implementations do return memory to the system: ChorusOS(?) apparently did. It's not clear if it moved the system break, or munmap()'ed
pages.
Here's a paper about a memory allocator that improves performance by "aggressively giving up free pages to the virtual memory manager". Slide show for a talk about the allocator.
Related videos on Youtube
michelle
Updated on September 18, 2022Comments
-
michelle over 1 year
I am running a C program on Linux 2.6.16 kernel. I do not think there are memory leaks in my program however the memory consumption for the program remains stable after certain operations and does not decrease. I use the 'ps v ' command to monitor the RSS value of my program.
The valgrind massif tool shows a large portion of heap is allocated by mmap in my process. But according to the code those allocations should have been freed after the operations are done. Is it because the freed memory is still mapped and/or still contributes to the RSS value of the process?
Any insight will be very appreciated!
Below is the snip from the valgrind massif report. Note I have turned on the --pages-as-heap option for the massif tool to measure all memories used by the program.
-------------------------------------------------------------------------------- n time(i) total(B) useful-heap(B) extra-heap(B) stacks(B) -------------------------------------------------------------------------------- 85 701,483,989,262 173,576,192 173,576,192 0 0 86 704,352,949,469 173,367,296 173,367,296 0 0 87 707,582,275,643 173,367,296 173,367,296 0 0 88 710,536,145,814 173,367,296 173,367,296 0 0 100.00% (173,367,296B) (page allocation syscalls) mmap/mremap/brk, --alloc-fns, etc. ->53.40% (92,581,888B) 0x649248B: mmap (in /lib64/tls/libc.so.6) | ->41.13% (71,303,168B) 0x6446D85: _int_malloc (in /lib64/tls/libc.so.6) | | ->39.31% (68,157,440B) 0x6448D62: calloc (in /lib64/tls/libc.so.6) ......[my own functions are omitted] ->35.28% (61,157,376B) 0x400F51B: mmap (in /lib64/ld-2.3.3.so) | ->28.81% (49,954,816B) 0x4004CE8: _dl_map_object_from_fd (in /lib64/ld-2.3.3.so) | | ->28.81% (49,954,816B) 0x400636B: _dl_map_object (in /lib64/ld-2.3.3.so) | | ->18.89% (32,755,712B) 0x400AB42: openaux (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x400AF7C: _dl_catch_error (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x4009FCF: _dl_map_object_deps (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x40021FD: dl_main (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x400E7F6: _dl_sysdep_start (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x4001477: _dl_start (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x4000CF6: ??? (in /lib64/ld-2.3.3.so) | | | ->18.89% (32,755,712B) 0x0: ??? | | | ->18.89% (32,755,712B) 0x7FF0003D5: ??? | | | ->18.89% (32,755,712B) 0x7FF0003E4: ??? | | | ......
-
Mikel over 11 yearsWhy aren't you using
munmap
? munmap(2) -
michelle over 11 yearsWe do not use munmap since glibc malloc and free has the implementations. Yes shared libraries are used. Why does that matter? The relevant parts of valgrind report is added to the main question.
-
Gilles 'SO- stop being evil' over 11 years
-
Mikel over 11 years@michelle I thought you meant you were calling
mmap
. But now I think I understand: You're callingmalloc
/calloc
, and it's callingmmap
? -
michelle over 11 yearsYes. the --pages-as-heap option for massif is set to yes to measure all the memory used by the program. Massif's normal heap block profiling is replaced by lower-level page profiling.
-
michelle over 11 yearsIs it true that a mmap'ed page for a process can be used by multiple malloc/calloc for different variables? If yes then it makes sense that when some variables are freed but not others then the page is still mapped for the process. Therefore valgrind still counts all variables of that page in its memory measurement?
-
-
michelle over 11 yearsI understand free() does not return memories to OS. But does free() unmap the memory or does the memory remain to be mapped by the glibc memory allocator?
-
michelle over 11 years"free() can't return a page to the operating system unless every sub-allocation is deallocated by the program." I do not really understand this. Could you explain 'sub-allocation'?
-
Admin over 11 years@michelle: suppose a page size of 4192 bytes. A program calls malloc(4186) and then malloc(8). The program has allocated all of a page. The program calls free() on the 4186-byte allocation. free() cannot unmap the page because the 8-byte-allocation has not been free()'ed.
-
michelle over 11 yearsThat makes sense. Thanks Bruce. So my guess is when the page is still mapped, all data in it are still taken into consideration by valgrind measurement though some are already freed. Correct?