性能工具gperftools使用说明-内存分配、检测和泄露分析

gperftools是google开发的一款非常实用的工具集,主要包括:
1.性能优异的malloc free内存分配器tcmalloc;
2.基于tcmalloc的堆内存检测和内存泄漏分析工具heap-profiler,heap-checker;
3.基于tcmalloc实现的程序CPU性能监测工具cpu-profiler.

上述所说的三种工具在我们服务器进程的性能分析监控,定位内存泄漏,寻找性能热点,提高malloc free内存分配性能的各个方面上都有非常成功的使用经验。

1.tcmalloc
以动态库或静态库的形式链接进你的可执行程序中
在上一边的代码中编译
g++ -o test test.cpp -lprofiler -lunwind

在tcmalloc中控制把未使用的内存还回给系统,主要是两个方法,
一种是修改环境变量TCMALLOC_RELEASE_RATE,这个值代表把未使用的内存还回给系统的速度吧,取值在0~10,值越高返还的速率越高,值为0表示从不返还,默认是1.0,其实是一个比较低的速率,所以在之前的表现中,就是很长一段时间内存降不下来。这个值的改变可以在程序运行期间就起作用。这种也有对应的函数调用SetMemoryReleaseRate,可以在程序代码中调用。
另外一种是一个函数调用:
MallocExtension::instance()->ReleaseFreeMemory();
这个函数如其名,把未使用的内存全部返还给系统。
以下完全参考官方文档http://google-perftools.googlecode.com/svn/trunk/doc/tcmalloc.html:

差异如下:

[root@nasSrv test]# g++ -o test test.cpp -lprofiler -lunwind -ltcmalloc
[root@nasSrv test]# ./test 
Finish!
PROFILE: interrupts/evictions/bytes = 133/0/256
[root@nasSrv test]# pprof --text test test.prof
Using local file test.
Using local file test.prof.
Total: 133 samples
      86  64.7%  64.7%       86  64.7% test2
      47  35.3% 100.0%       47  35.3% test1
       0   0.0% 100.0%      133 100.0% __libc_start_main
       0   0.0% 100.0%      133 100.0% main
       0   0.0% 100.0%      133 100.0% test3
[root@nasSrv test]# g++ -o test test.cpp -lprofiler -lunwind
[root@nasSrv test]# ./test 
Finish!
PROFILE: interrupts/evictions/bytes = 133/6/544
[root@nasSrv test]# pprof --text test test.prof             
Using local file test.
Using local file test.prof.
Total: 133 samples
      91  68.4%  68.4%       91  68.4% test2
      42  31.6% 100.0%       42  31.6% test1
       0   0.0% 100.0%      133 100.0% __libc_start_main
       0   0.0% 100.0%      133 100.0% main
       0   0.0% 100.0%      133 100.0% test3

2.heap-profiler, heap-checker
这两个工具其实挺像的,heap-checker专门检测内存泄漏,heap-profiler则是内存监控器,可以随时知道当前内存使用情况(程序中内存使用热点),当然也能检测内存泄漏。我们工作中一直是使用heap-profiler,实时监控程序的内存使用情况。
文档在此:http://google-perftools.googlecode.com/svn/trunk/doc/heapprofile.html

heap-profiler是基于tcmalloc的,正规开启它的方法是在代码中调用 HeapProfilerStart方法,参数是profile文件前缀名,相应的关闭则需调用 HeapProfilerStop。前面有介绍过我们的服务器有运行时执行自定义命令的机制,我们把两个命令MemProfilerStart,MemProfilerStop实现成调用上述相应的开启/关闭heap-profiler的API,这样我们可以在服务器运行时,随时开启和关闭heap-profiler,非常方便的查看当前程序内存使用情况。

heap-profiler会在每当一定量的内存被新申请分配出来时或者当一段固定时间过去后,输出含有当前内存使用情况的profile文件,文件名类似这种:
%prefix%.0000.heap
%prefix%.0001.heap
%prefix%.0002.heap

prefix是前文所说的profile数据文件的前缀,如果并没有指定成绝对路径则会在你的程序的工作目录中生成,这些文件可以被一个脚本工具pprof解析输出成各种可视的数据格式文件,pprof使用了dot语言绘图,需要安装graphviz
pprof也是下文解析CPU profile文件的工具,pprof工具可以把profile信息输出成多种格式,如pdf,png,txt等,如果是以图的形式显示,则是根据调用堆栈的有向图,像下图这样:

这个图里面每个节点代表一个函数调用,比如GFS_MasterChunkTableUpdateState节点,176.2(17%) of 729.9(70%) 大致表示这个函数本身自己直接消耗了17%的内存,加上子调用共消耗了70%的内存,然后每条边则显示每个子调用花费了多少内存。因为我们的linux系统并未安装图形界面,通常都是直接生成了txt文件:

% pprof --text gfs_master /tmp/profile.0100.heap
   255.6  24.7%  24.7%    255.6  24.7% GFS_MasterChunk::AddServer
   184.6  17.8%  42.5%    298.8  28.8% GFS_MasterChunkTable::Create
   176.2  17.0%  59.5%    729.9  70.5% GFS_MasterChunkTable::UpdateState
   169.8  16.4%  75.9%    169.8  16.4% PendingClone::PendingClone
    76.3   7.4%  83.3%     76.3   7.4% __default_alloc_template::_S_chunk_alloc
    49.5   4.8%  88.0%     49.5   4.8% hashtable::resize  

第一列代表这个函数调用本身直接使用了多少内存,第二列表示第一列的百分比,第三列是从第一行到当前行的所有第二列之和,第四列表示这个函数调用自己直接使用加上所有子调用使用的内存总和,第五列是第四列的百分比。基本上只要知道这些,就能很好的掌握每一时刻程序运行内存使用情况了,并且对比不同时段的不同profile数据,可以分析出内存走向,进而定位热点和泄漏。

在我们的实践中,也经常发现一些环境变量非常有用:
HEAP_PROFILE_ALLOCATION_INTERVAL:上文说每当一定量的内存被新申请分配出来时,就会输出profile文件,这个变量值就是控制多少字节,默认是(1024*1024*1024)1GB,粒度相对比较大,常常会被我们调整为几百MB甚至更小。
HEAP_PROFILE_MMAP:有时候程序申请内存的方式是通过mmap,sbrk系统调用而不是malloc free,如果想profile这些内存,可以开启这个变量,默认是false。我们工程代码中就有些调用了mmap申请大块内存的地方,开启这个环境变量,能更准确跟踪内存走向。
HEAP_PROFILE_MMAP_ONLY:如其名,只profile mmap,sbrk申请的内存。
更改这些环境变量是可以在启动命令中完成的:
% env HEAPPROFILE=/tmp/mybin.hprof /usr/local/bin/my_binary_compiled_with_tcmalloc

关于Zeno Chen

本人涉及的领域较多,杂而不精 程序设计语言: Perl, Java, PHP, Python; 数据库系统: MySQL,Oracle; 偶尔做做电路板的开发,主攻STM32单片机
此条目发表在C/C++分类目录。将固定链接加入收藏夹。