强制 free() 到 return malloc 内存回到 OS

Force free() to return malloc memory back to OS

似乎即使在我为 malloc() 分配的 Linux 进程释放所有内存之后, 内存仍然保留给进程,而不是 returned 到 OS.

运行 valgrind massif 工具默认显示无泄漏。

运行 valgrind--pages-as-heap=yes 揭示了这一点:

->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 而没有 return 调用 OS。

如何强制 free() 立即调用 sbrk() 并将 return 所有内存返回给 OS?

我 运行 在非常低端的平台上,每个 MB 都很重要。

提前致谢。

让 OS 回收内存的唯一可靠且便携的方法是 退出进程 并重新启动它,恢复您需要继续的任何状态。

当然,根据您的需要使用 brk/sbrk 编写您自己的 malloc/free 实现是另一种选择。

使用 glibc malloc 尝试调用 malloc_trim 函数。它没有很好的记录,并且在 2007 年左右 (glibc 2.9) 内部发生了变化 - .

自 2007 年以来,此功能将: 遍历所有 malloc 内存区域(用于多线程应用程序)进行 trim 和 fastbin 合并;并完全释放所有对齐的 (4KB) 页面。

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

因此,调用 malloc_trim 会将几乎所有释放的内存释放回 OS。仅保留包含尚未释放数据的页面;当使用 MADV_DONTNEED 时,OS 可能取消映射或不取消映射物理页面,而 linux 通常取消映射。疯狂的页面仍然计入 VSIZE(进程的总虚拟内存大小),但通常有助于减少 RSS(进程使用的物理内存量)。

或者,您可以尝试切换到替代 malloc 库:tcmalloc (gperftools / google-perftools) 或 jemalloc (facebook),它们都有将释放的内存返回到 [=34 的积极规则=](使用 madvise MADV_DONTNEED 甚至 MADV_FREE)。