malloc实现是否将释放的内存返回给系统?

我有一个长期生活的应用程序与频繁的内存分配 – 释放。 任何malloc实现返回将内存释放回系统?

在这方面,什么是这样的行为:

  • ptmalloc 1,2(glibc默认)或3
  • dlmalloc
  • tcmalloc(谷歌线程malloc)
  • solaris 10-11默认的malloc和mtmalloc
  • FreeBSD 8默认的malloc(jemalloc)
  • 囤地malloc?

更新

如果我的应用程序的内存消耗在白天和夜晚可能会非常不同(例如),我可以强制任何malloc将释放的内存返回给系统吗?

没有这样的返回释放内存将被换出,并在很多时候,但这样的内存只包含垃圾。

以下分析仅适用于glibc(基于ptmalloc2algorithm)。 有些选项似乎有助于将释放的内存返回给系统:

  1. mallopt() (在malloc.h定义)确实提供了使用参数选项M_TRIM_THRESHOLD之一来设置修剪阈值的选项,这表示数据段顶部允许的最小可用内存量(以字节为单位)。 如果数量低于这个阈值,glibc调用brk()将内存返回给内核。

    Linux中M_TRIM_THRESHOLD的默认值设置为128K,设置较小的值可能会节省空间。

    通过在环境variablesMALLOC_TRIM_THRESHOLD_设置微调阈值,可以实现同样的行为,绝对不会有源变化。

    然而,使用M_TRIM_THRESHOLD运行的初步testing程序显示,即使malloc分配的内存返回到系统,通过brk()最初请求的实际内存块(竞技场)的剩余部分往往被保留。

  2. 可以通过调用malloc_trim(pad) (在malloc.h定义)来修剪内存领域并将任何未使用的内存返回给系统。 此函数调整数据段的大小,至less在其末尾pad字节,如果less于一页的字节可以被释放,则失败。 分段大小始终是一个页面的倍数,在i386上是4,096字节。

    使用malloc_trimfree()这种修改行为的malloc_trim可以使用malloc挂钩function来完成。 这不需要对核心glibc库进行任何源代码更改。

  3. 使用madvise()系统调用里面的免费执行glibc。

大多数实现并不需要标识那些(相对less见的)整个“块”(无论大小适合OS)是否已经被释放并且可以被返回的情况,但是当然也有例外。 例如,我引用了 OpenBSD中的wikipedia页面 :

free调用中,使用munmap释放内存并从进程地址空间取消映射。 该系统旨在通过利用作为OpenBSD的mmap系统调用的一部分实现的地址空间布局随机化和间隙页面特性来提高安全性,并检测使用后释放的错误 – 因为大内存分配完全没有映射释放,进一步使用导致分段错误和程序终止。

不过,大多数系统并不像OpenBSD那样注重安全性。

知道这一点,当我编写一个长期运行的系统,对大量的内存有一个已知的过渡性的要求时,我总是试图fork这个过程:父母然后等待孩子的结果[ [通常在pipe道上]],子进行计算(包括内存分配),返回结果[[在pipe道上]],然后终止。 这样一来,我的漫长的过程不会在长时间的记忆需求偶然的“尖峰”之间浪费记忆。 其他的替代策略包括切换到一个自定义的内存分配器,以满足这样的特殊需求(C ++使得它相当容易,但是具有Java和Python的底层虚拟机的语言通常不会)。

我正在处理与OP相同的问题。 到目前为止,tcmalloc似乎是可能的。 我发现两个解决scheme:

  1. 用tcmalloc链接编译你的程序,然后启动它:

     env TCMALLOC_RELEASE=100 ./my_pthread_soft 

    文档提到了这一点

    合理的利率在[0,10]范围内。

    但是10对我来说似乎还不够(即我看不到变化)。

  2. 在代码中find释放所有释放的内存有趣的地方,然后添加下面的代码:

     #include "google/malloc_extension_c.h" // C include #include "google/malloc_extension.h" // C++ include /* ... */ MallocExtension_ReleaseFreeMemory(); 

第二种解决scheme对我来说非常有效, 第一个很好,但不是很成功,例如find合适的号码很复杂。

对于所有'正常'的malloc,包括你提到的malloc,释放内存以供你的进程重用,但不能回溯到整个系统。 只有当你的进程终于被终止时,才会释放回整个系统。

在你列出的那些中,只有Hoard会把内存返回给系统,但是如果它实际上可以做到这一点将取决于你的程序的分配行为。

我有一个类似的问题,在我的应用程序,经过一些调查后,我注意到,由于某种原因,当分配的对象很小(在我的情况下,小于120字节),glibc不会将内存返回给系统。
看看这个代码:

 #include <list> #include <malloc.h> template<size_t s> class x{char x[s];}; int main(int argc,char** argv){ typedef x<100> X; std::list<X> lx; for(size_t i = 0; i < 500000;++i){ lx.push_back(X()); } lx.clear(); malloc_stats(); return 0; } 

节目输出:

 Arena 0: system bytes = 64069632 in use bytes = 0 Total (incl. mmap): system bytes = 64069632 in use bytes = 0 max mmap regions = 0 max mmap bytes = 0 

大约64 MB不返回到系统。 当我将typedef更改为: typedef x<110> X; 程序输出如下所示:

 Arena 0: system bytes = 135168 in use bytes = 0 Total (incl. mmap): system bytes = 135168 in use bytes = 0 max mmap regions = 0 max mmap bytes = 0 

几乎所有的记忆都被释放了。 我也注意到在任何情况下使用malloc_trim(0)释放内存到系统。
这里是将malloc_trim添加到上面的代码后的输出:

 Arena 0: system bytes = 4096 in use bytes = 0 Total (incl. mmap): system bytes = 4096 in use bytes = 0 max mmap regions = 0 max mmap bytes = 0 

简短的回答:要强制malloc子系统将内存返回到操作系统,请使用malloc_trim()。 否则,返回内存的行为是依赖于实现的。

Interesting Posts