tcmalloc的碎片化

时间:2013-03-22 08:46:55

标签: c++ linux glibc fragmentation tcmalloc

我们的软件实现了一个actor模型系统,我们经常分配/释放小对象。我非常确定每个对象都会在没有内存泄漏的情况下被销毁。 (我使用了valgrind和tcmalloc工具来检查我的软件中的内存泄漏。没有发现泄漏。)

当我们更改为使用tcmalloc替换glibc中的malloc时,我们发现内存不断增加,直到该进程被OOM(内存不足)终止。 然后我们发现glibc也有同样的问题,但增长率低于tcmalloc。

我使用malloc_stats()来显示内存信息

首次执行后(顶部显示0.96G)'


  • MALLOC:960110592(915.6 MB)堆大小
  • MALLOC:15886016(15.2 MB)应用程序使用的字节
  • MALLOC:907419648(865.4 MB)页面堆中的字节数
  • MALLOC:0(0.0 MB)未在页面堆中映射的字节
  • MALLOC:27121208(25.9 MB)中央缓存中的字节数
  • MALLOC:151040(0.1 MB)转移缓存中的字节数
  • MALLOC:9532680(9.1 MB)线程缓存中的字节数
  • MALLOC:14275 Spans in use
  • MALLOC:正在使用27个线程堆
  • MALLOC:7602176(7.2 MB)已分配元数据

第5次同样执行后(顶部显示1.2G)

  • MALLOC:1173131264(1118.8 MB)堆大小
  • MALLOC:18001048(17.2 MB)应用程序使用的字节
  • MALLOC:1082458112(1032.3 MB)页面堆中的字节数
  • MALLOC:21168128(20.2 MB)未在页面堆中映射的字节
  • MALLOC:37992328(36.2 MB)中央缓存中的字节数
  • MALLOC:252928(0.2 MB)转移缓存中的字节数
  • MALLOC:13258720(12.6 MB)线程缓存中的字节数
  • MALLOC:17651 Spans in use
  • MALLOC:正在使用27个线程堆
  • MALLOC:8126464(7.8 MB)已分配元数据

从这样的数据我们可以看出。 在第5次相同的行为之后,我们的软件中只使用了17.2。但tcmalloc保持1.1G内存而不返回系统。当然,tcmalloc保持那些记忆并不重要。 但是当我们的程序被OOM杀死时(实际使用的内存小于1G),它会不断增加。

我们怀疑它与堆碎片有关。 有人有经验可以与我们分享? 我想我有同样的情况 https://bugzilla.redhat.com/show_bug.cgi?id=843478

非常感谢。

2 个答案:

答案 0 :(得分:1)

我建议您在应用中使用Boehm's conservative GC并使用GC_MALLOCGC_MALLOC_ATOMIC代替malloc(而GC_FREE代替free,但是你甚至可以避免任何明确的free,GC会做到这一点。或者可以使用valgrind(使用系统Glibc malloc)来查找内存泄漏。如果使用Boehm的GC,请不要忘记明确清除分配的内存区域。

最好确保您的许多小物件具有粗粒度。例如。分配8或12或16个单词的对象,而不是8,9,10,11,12,13,14,15或16个单词的对象...例如,您可能只分配一些大小为2或3的幂的区域倍于2的力量。

此外,请不要忘记您可以使用setrlimit(2)限制内存空间,例如在终端中运行bash的内置ulimit。这应该简化测试。此外,使用pmap/proc/$(pidof yourapp)/maps可能有助于您了解所使用的地址空间。

PS。 Boehm GC,无论任何类型的malloc(包括tcmalloc或Glibc malloc)都不能解决内存碎片问题。如果您怀疑存在碎片,则必须在地址空间中移动内存区域(即您可能希望编写自己的精确,复制,分代GC或重新使用现有GC)。

答案 1 :(得分:1)

tcmalloc尝试做一些聪明的事情来预测你的内存使用,但是即使你已经释放内存,将内存释放回系统也不是很好。事实上,它可能驻留在内存中并导致OOM。

这样做:

MallocExtension ::实例() - > ReleaseFreeMemory();

当你的应用程序预计会释放它预计不会很快使用的内存时。

请查看“将内存释放回系统”部分以获取更多信息 http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html

还有其他方法,例如设置发布速率,但作为一个开始,您可以在代码中使用它,并检查驻留内存是否按预期停机。