陪你度过漫长岁月

技术总结《使用gperftools排查内存泄漏》

前言

内存泄漏可以说是很典型的问题了,有一个好用的工具去排查内存泄漏是比较重要的。本文主要介绍的是gperftools这个工具。

gperftools这个工具比较轻量级,对源码是无侵入的,只需要重新链接即可。

接下来按照安装,以及使用两部分展开,最后再补充一个使用gperftools做性能分析的例子。


安装

ubuntu使用下面这个脚本就能直接安装了。跑完之后可以通过ls /usr/local/lib/ | grep tcmalloc来确认是否安装成功。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#!/bin/bash
SCRIPT=`realpath $0`
SCRIPTPATH=`dirname $SCRIPT`
sudo apt update
sudo apt install -y autoconf libtool ghostscript graphviz
cd /tmp
git clone https://github.com/gperftools/gperftools.git
cd gperftools
./autogen.sh
./configure CC=/usr/bin/gcc
make -j1
sudo make install
sudo ldconfig

内存泄漏

demo代码

以下demo代码想表达的意思是gperftools有能力检测出没有被释放的内存(heal_leak函数里面有没有delete的指针)。从中也可以看到,gperftools查内存泄漏对源码完全是无侵入的,只需要重新链接一下就可以了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
// test_heap.cpp
#include <iostream>
using namespace std;
void heap_normal() {
int i;
for (i=0; i<1024*1024; ++i) {
int* p = new int;
delete p;
}
}
void heap_leak() {
int i;
for (i=0; i<1024*1024; ++i) {
int* p = new int;
//delete p;
}
}
void heap_func() {
heap_normal();
heap_leak();
}
int main(){
heap_func();
return 0;
}

测试指令

1
2
3
g++ test_heap.cpp -o test -ltcmalloc
HEAPPROFILE=./heap_profile ./test
/usr/local/bin/pprof --pdf test ./*.heap > heap_profile.pdf

结果

输出的heap_profile.pdf长这个样子,可以很清晰地看到heap_leak中没被释放的内存,而不包含heap_normal中被正常释放的内存:


heap_profile.pdf

性能分析

demo代码

这里要注意的是代码里面加了一段dummy code,目的是使用profiler的代码,以保证正常链接。不加的话,对libprofiler.so的链接有可能会被优化掉,导致最后profile失败。

这个跟链接器是强相关的,在有的机子上是不需要加的,这里写出来只是以防万一。

建议是先不加,然后通过ldd test看是否有libprofiler.so,如果有的话就不需要加dummy code了。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
// test_cpu.cpp
#include <gperftools/profiler.h>
#include <iostream>
using namespace std;
void cpu_func1() {
int i = 0;
while (i < 100000) {
++i;
}
}
void cpu_func2() {
int i = 0;
while (i < 200000) {
++i;
}
}
void cpu_func() {
for (int i = 0; i < 1000; ++i) {
cpu_func1();
cpu_func2();
}
}
void dummy_code() {
ProfilerStart("./dummy.log");
ProfilerStop();
}
int main(){
cpu_func();
return 0;
}

测试指令

1
2
3
g++ test_cpu.cpp -o test -lprofiler
CPUPROFILE=./cpu_profile ./test
/usr/local/bin/pprof --pdf test cpu_profile > cpu_profile.pdf

结果

输出的cpu_profile.pdf长这个样子:


cpu_profile.pdf

参考