9

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: ???
| |   |
......
7
  • Why aren't you using munmap? munmap(2)
    – Mikel
    Oct 31, 2012 at 20:49
  • Are you using shared libraries? Can you provide relevant parts of output from valgrind as well as /proc/<PID>/maps?
    – Mikel
    Oct 31, 2012 at 21:08
  • 1
    We 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.
    – michelle
    Oct 31, 2012 at 23:06
  • @michelle I thought you meant you were calling mmap. But now I think I understand: You're calling malloc/calloc, and it's calling mmap?
    – Mikel
    Nov 1, 2012 at 2:00

1 Answer 1

6

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.

4
  • I 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
    Oct 31, 2012 at 19:43
  • "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'?
    – michelle
    Oct 31, 2012 at 19:45
  • 2
    @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.
    – user732
    Oct 31, 2012 at 20:58
  • That 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?
    – michelle
    Nov 1, 2012 at 12:24

You must log in to answer this question.

Not the answer you're looking for? Browse other questions tagged .