生产环境tcmalloc 缓存回收

Linux Debugging (九) 一次生产环境下的“内存泄露”

anzhsoft  2014-11-17 20:45:00  浏览685  评论0

摘要: 一个偶然的机会,发现一个进程使用了超过14G的内存。这个进程是一个RPC server,只是作为中转,绝对不应该使用这么多内存的。即使并发量太多,存在内存中的数据太多,那么在并发减少的情况下,这个内存使用肯定会降下来。

一个偶然的机会,发现一个进程使用了超过14G的内存。这个进程是一个RPC server,只是作为中转,绝对不应该使用这么多内存的。即使并发量太多,存在内存中的数据太多,那么在并发减少的情况下,这个内存使用肯定会降下来。但是事实上,这个内存会一直涨,直到被OOM Killer杀掉。


由于这个rpc server的逻辑比较简单,先走读源码,除了发现一些简单的编程上面的问题外,没有大的问题。先上valgrind:

valgrind --tool=memcheck --leak-check=full -v ./rpc_server

原来的情况是,一般都会检查出内存泄露的。这次没有(否则也不会有本文了):



实际上至少10G的“内存泄露”。既然没有检查出,说明这些内存还是活着的。设想一下这个场景:每个请求都new一块内存,放到一个列表中。正常的话请求处理完需要从这个列表中删除这块内存。如果没有删除,那么这就算是内存泄露。但是valgrind检查不出来。


由于上面这个进程使用了tcmalloc,是不是tcmalloc的问题?我们知道tcmalloc的效率要优于malloc,那么是不是tcmalloc的问题,如果它一直申请内存,不释放,就会造成这种”内存泄露“。注意下面一段话:

Releasing Memory Back to the System

By default, tcmalloc will release no-longer-used memory back to the kernel gradually, 
over time.
The tcmalloc_release_rate flag controls how quickly this happens. 
You can also force a release at a given point in the progam execution like so:

   MallocExtension::instance()->ReleaseFreeMemory();
You can also call SetMemoryReleaseRate() to change the tcmalloc_release_rate value
 at runtime, or GetMemoryReleaseRate to see what the current release rate is.

简单翻译一下,就是tcmalloc将内存交回OS的机制:默认情况下,tcmalloc会将长时间未用的内存交还系统。tcmalloc_release_rate这个flag控制了这个交回频率。你可以在运行时通过这个语句强制这个release发生:

 MallocExtension::instance()->ReleaseFreeMemory();

当然了,你可以通过 SetMemoryReleaseRate()  来设置这个tcmalloc_release_rate. 如果设置为0,代表永远不交回。数字越大代表交回的频率越大。一般合理的值就是设置一个0 - 10 之间的一个数。也可以通过设置环境变量 TCMALLOC_RELEASE_RATE来设置这个rate。

带着这个怀疑,首先还是通过Google's gpreftools 检查一下heap的使用情况:

1.  export HEAPCHECK=draconian

2.  export PPROF_PATH=/usr/local/bin/pprof

直接启动即可。

之所以设置为draconian,因为想得到更详细的统计信息。更将相信的解释如下:Flavors of Heap Checking


These are the legal values when running a whole-program heap check:

  1. minimal
  2. normal
  3. strict
  4. draconian

"Minimal" heap-checking starts as late as possible in a initialization, meaning you can leak some memory in your initialization routines (that run before main(), say), and not trigger a leak message. If you frequently (and purposefully) leak data in one-time global initializers, "minimal" mode is useful for you. Otherwise, you should avoid it for stricter modes.

"Normal" heap-checking tracks live objects and reports a leak for any data that is not reachable via a live object when the program exits.

"Strict" heap-checking is much like "normal" but has a few extra checks that memory isn't lost in global destructors. In particular, if you have a global variable that allocates memory during program execution, and then "forgets" about the memory in the global destructor (say, by setting the pointer to it to NULL) without freeing it, that will prompt a leak message in "strict" mode, though not in "normal" mode.

"Draconian" heap-checking is appropriate for those who like to be very precise about their memory management, and want the heap-checker to help them enforce it. In "draconian" mode, the heap-checker does not do "live object" checking at all, so it reports a leak unless all allocated memory is freed before program exit. (However, you can use IgnoreObject() to re-enable liveness-checking on an object-by-object basis.)

"Normal" mode, as the name implies, is the one used most often at Google. It's appropriate for everyday heap-checking use.

In addition, there are two other possible modes:

  • as-is
  • local

as-is is the most flexible mode; it allows you to specify the various knobs of the heap checker explicitly. local activates the explicit heap-check instrumentation, but does not turn on any whole-program leak checking.

但是很不幸,还是没有检查出来:



上面的泄露统计不是预期的,因为“泄露”了至少10G的内存了。

那么还是强制的释放不用的buffer吧:

MallocExtension::instance()->ReleaseFreeMemory();

问题解决了。
版权声明:本文内容由互联网用户自发贡献,本社区不拥有所有权,也不承担相关法律责任。如果您发现本社区中有涉嫌抄袭的内容,欢迎发送邮件至: yqgroup@service.aliyun.com 进行举报,并提供相关证据,一经查实,本社区将立刻删除涉嫌侵权内容。
  • 0
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
TCMalloc是一个由Google开发的内存管理器,被广泛用于大规模的分布式系统中。它为多线程环境下的内存分和释放提供了高效的性能。 TCMalloc的实现主要包含以下几个关键特性: 1. Thread-Caching TCMalloc使用了线程本地缓存(Thread-Caching)的机制,每个线程都维护了一个本地缓存,用于快速分配和释放内存。这样可以避免不同线程之间频繁访问共享数据结构的开销,提高了内存分配和释放的性能。 2. Central Cache TCMalloc还维护了一个全局的中央缓存(Central Cache),用于存储较大的内存块。当本地缓存不足以满足内存需求时,线程会向中央缓存申请内存。 3. Page Heap TCMalloc使用了Page Heap来管理内存。Page Heap将内存按页进行划分,并使用位图来跟踪每个页的使用情况。这样可以提高内存分配和释放的效率,并减少内存碎片化。 4. Size Class TCMalloc将需要分配的内存按照大小进行分类,每个大小类都有一个对应的内存池。这样可以提高内存分配和释放的效率,并减少内存碎片化。 5. 高效的内存分配和释放算法 TCMalloc使用了一些高效的算法来管理内存,如位图、堆栈缓存等。这些算法能够快速地分配和释放内存,并且减少内存碎片化。 总的来说,TCMalloc通过使用线程本地缓存、中央缓存、Page Heap以及高效的内存分配和释放算法,实现了高性能的内存管理。它在Google的大规模分布式系统中得到了广泛应用,并取得了很好的效果。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值