即使我释放了由malloc()分配的Linux进程的所有内存, 内存仍为进程保留,不会返回给操作系统。
默认情况下运行valgrind massif工具不会泄漏。
使用--pages-as-heap = yes运行valgrind会显示:
- > 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)
所以即使内存已经被free()释放了,似乎malloc也调用了brk / sbrk而没有将它返回给操作系统。
如何强制free()立即调用sbrk()并将所有内存返回给操作系统?
我正在一个非常低端的平台上运行,每个MB都很重要。
提前致谢。
答案 0 :(得分:5)
让OS回收内存的唯一可靠且可移植的方法是退出进程并重新启动它,恢复您需要继续的任何状态。
当然,根据您的需要使用brk / sbrk编写自己的malloc / free实现是另一种选择。
答案 1 :(得分:3)
使用glibc malloc尝试调用malloc_trim
函数。它没有很好的记录,并且在2007年左右它内部发生了变化(glibc 2.9) - https://stackoverflow.com/a/42281428。
自2007年以来,这个功能将:迭代所有malloc内存竞技场(用于多线程应用程序)进行修剪和快速整合;并释放完全释放的所有对齐(4KB)页面。
Ulrich Drepper 太阳,2007年12月16日22:53:08 +0000(22:53 +0000)
- malloc / malloc.c(public_mTRIm):遍历所有竞技场并为所有竞技场调用mTRIm。
(mTRIm):另外迭代所有空闲块并使用madvise 为所有包含至少一个的块释放内存 记忆页面。
+ 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);
因此,调用malloc_trim
会将几乎所有释放的内存释放回操作系统。只保留包含尚未释放数据的页面;当使用MADV_DONTNEED进行新手操作时,操作系统可能会取消映射或不取消映射物理页面,而linux通常会取消映射。 Madvised页面仍然计入VSIZE(进程的总虚拟内存大小),但通常有助于减少RSS(进程使用的物理内存量)。
或者,您可以尝试切换到另一个malloc库:tcmalloc(gperftools / google-perftools)或jemalloc(facebook),它们都具有将释放的内存返回OS的激进规则(使用madvise MADV_DONTNEED甚至{{ 3}})。