【问题标题】:Force free() to return malloc memory back to OS强制 free() 将 malloc 内存返回给操作系统
【发布时间】:2015-03-12 19:24:28
【问题描述】:

似乎即使在我为malloc()分配的Linux进程释放了所有内存之后, 内存仍然为进程保留,不返回给操作系统。

默认运行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 并且没有将其返回给操作系统。

如何强制free() 立即调用sbrk() 并将所有内存返回给操作系统?

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

提前致谢。

【问题讨论】:

  • malloc - 内存分配。它只是分配,它不会“释放”内存以供重复使用,这就是 free() 的原因。
  • 嗯,似乎这可能是解决方案:stackoverflow.com/questions/2215259/…
  • 这不是您的程序或malloc/free 调用的问题,而是将先前分配的内存页面映射到您的进程的操作系统。如果操作系统需要这些空闲页面,它会在需要时使用它们。我懒得找重复了,但是这个问题有很多重复。
  • @JoachimPileborg 实际上这显然不起作用。我从 Linux 内核崩溃说没有足够的内存。当我用 fork 调用我的进程并且它被杀死时,sbrk 被释放并且我能够继续。所以操作系统没有调用 sbrk 来释放之前释放的内存

标签: c linux memory memory-management glibc


【解决方案1】:

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

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

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

乌尔里希·德雷珀 2007 年 12 月 16 日星期日 22:53:08 +0000 (22:53 +0000)

  • malloc/malloc.c (public_mTRIm):遍历所有 arenas 并为所有它们调用 mTRIm。

(mTRIm):另外遍历所有空闲块并使用 madvise 为所有包含至少一个块的块释放内存 内存页。

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 会将几乎所有已释放的内存释放回操作系统。仅保留包含仍未释放数据的页面;当使用 MADV_DONTNEED 和 linux 通常会取消映射时,操作系统可能会取消映射或不取消映射物理页面。 madvised pages 仍然计入 VSIZE(进程的总虚拟内存大小),但通常有助于减少 RSS(进程使用的物理内存量)。

或者,您可以尝试切换到替代 malloc 库:tcmalloc (gperftools / google-perftools) 或 jemalloc (facebook),它们都有将释放的内存返回给操作系统的激进规则(使用 madvise MADV_DONTNEED 甚至 @987654324 @)。

【讨论】:

    【解决方案2】:

    让操作系统回收内存的唯一可靠且可移植的方法是退出进程并再次重新启动它,恢复您需要继续的任何状态。

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

    【讨论】:

      猜你喜欢
      • 2011-09-23
      • 2021-04-05
      • 1970-01-01
      • 1970-01-01
      • 2011-02-19
      • 1970-01-01
      • 1970-01-01
      • 2012-08-16
      相关资源
      最近更新 更多