线上服务出现了内存泄漏,记录一下使用jemalloc查问题的过程
- 平台:linux
- 语言: c++
原理
经过设置,jemalloc会每增长一些内存dump出内存情况。因为内存泄漏,程序内存越来越高,取一段时间前后dump出的两个文件,通过jemallc提供的工具画出diff图,就可以看到内存增长在哪里
安装jemalloc
wget https://github.com/jemalloc/jemalloc/archive/5.1.0.tar.gz
tar zxvf 5.1.0.tar.gz
cd jemalloc-5.1.0/
./autogen.sh
./configure --prefix=/usr/local/jemalloc-5.1.0 --enable-prof
make -j
make install
注意要--enable-prof
才行
让程序链接新安装的jemalloc
我这里是删了程序目录下的jemalloc.a静态库文件,然后改程序的CMakeList
文件
set(MODULE_SHARED_LIB
jemalloc
...
)
target_link_libraries(
...
-Wl,-Bdynamic
${MODULE_SHARED_LIB}
)
然后重新编译
运行文件
先修改一下环境变量,lg_prof_interval:26
表明每增长2^26字节(64M)大小进行一次dump
export MALLOC_CONF="prof:true,lg_prof_interval:26"
然后运行bin文件
LD_PRELOAD=/usr/local/jemalloc-5.1.0/lib/libjemalloc.so.2 ./a.out
时间够了以后,停掉程序。经过一段时间运行,目录下就有很多.heap
文件,运行20分钟,取最开始和最后面的两个画图比较
usr/local/jemalloc-5.1.0/bin/jeprof --pdf a.out --base=jeprof.start.heap jeprof.end.heap > a.pdf
后续工作就是打开pdf文件结合代码分析了,公司的图不方便放,这里放一张网图,下图表明多出来了700+m内存,都是main函数里分配的,其中在大多都是map的[]
的操作符重载函数中占用了514.5MB
思考
- 这次泄漏的原因是
对裸指针容器使用了erase()函数
,这并不会删除指针指向的数据 - 通过jemalloc画出来的图能定位泄漏的内存是在哪分配的,一般能定位到函数,但具体在哪应该被删除却没有,还是要自己去找,不要盯着分配的函数看,要追踪分配出的数据结构后续的使用
- 发现内存泄漏尽快修,时间太久连哪次commit造成的都不知道了
后记
今天又查了个内存泄漏,其实并不是内存泄漏,内部有一个queue
,属于多生产单消费,用jemalloc
分析发现它占用内存极大,原因竟然是消费能力不足,导致queue堆积,思考如下:
- 内存增长不一定是代码里new了没有delete造成内存泄漏,还可能是消费能力不足导致内存堆积
- 如果发现某数据结构内存增加,多在日志中打印其size看看