jemalloc检查c++服务内存泄漏

4,021 阅读2分钟

线上服务出现了内存泄漏,记录一下使用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

image.png

思考

  • 这次泄漏的原因是对裸指针容器使用了erase()函数,这并不会删除指针指向的数据
  • 通过jemalloc画出来的图能定位泄漏的内存是在哪分配的,一般能定位到函数,但具体在哪应该被删除却没有,还是要自己去找,不要盯着分配的函数看,要追踪分配出的数据结构后续的使用
  • 发现内存泄漏尽快修,时间太久连哪次commit造成的都不知道了

后记

今天又查了个内存泄漏,其实并不是内存泄漏,内部有一个queue,属于多生产单消费,用jemalloc分析发现它占用内存极大,原因竟然是消费能力不足,导致queue堆积,思考如下:

  • 内存增长不一定是代码里new了没有delete造成内存泄漏,还可能是消费能力不足导致内存堆积
  • 如果发现某数据结构内存增加,多在日志中打印其size看看