原创:扣钉日记(微信公众号ID:codelogs),欢迎分享,非公众号转载保留此声明。
简介
在上篇文章中,介绍了使用tcmalloc或jemalloc定位native内存泄露的方法,但使用这个方法相当于更换了原生内存分配器,以至于使用时会有一些顾虑。
经过一些摸索,发现glibc自带的ptmalloc2分配器,也提供有追踪内存泄露的机制,即mtrace,这使得发生内存泄露时,可直接定位,而不需要额外安装及重启操作。
mtrace追踪内存泄露
glibc中提供了mtrace这个函数来开启追踪内存分配的功能,开启后每次应用程序调用malloc或free函数时,会将内存分配释放操作记录在MALLOC_TRACE环境变量所指的文件里面,如下:
$ pid=`pgrep java`
# 配置gdb不调试信号,避免JVM收到信号后被gdb暂停
$ cat <<"EOF" > ~/.gdbinit
handle all nostop noprint pass
handle SIGINT stop print nopass
EOF
# 设置MALLOC_TRACE环境变量,将内存分配操作记录在malloc_trace.log里
$ gdb -q -batch -ex 'call setenv("MALLOC_TRACE", "./malloc_trace.log", 1)' -p $pid
# 调用mtrace开启内存分配追踪
$ gdb -q -batch -ex 'call mtrace()' -p $pid
# 一段时间后,调用muntrace关闭追踪
$ gdb -q -batch -ex 'call muntrace()' -p $pid
然后查看malloc_trace.log,内容如下:
可以发现,在开启mtrace后,glibc将所有malloc、free操作都记录了下来,通过从日志中找出哪些地方执行了malloc后没有free,即是内存泄露点。
于是glibc又提供了一个mtrace命令,其作用就是找出上面说的执行了malloc后没有free的记录,如下:
$ mtrace malloc_trace.log | less -n
Memory not freed:
-----------------
Address Size Caller
0x00007efe08008cc0 0x18 at 0x7efe726e8e5d
0x00007efe08008ea0 0x160 at 0x7efe726e8e5d
0x00007efe6cabca40 0x58 at 0x7efe715dc432
0x00007efe6caa9ad0 0x1bf8 at 0x7efe715e4b88
0x00007efe6caab6d0 0x1bf8 at 0x7efe715e4b88
0x00007efe6ca679c0 0x8000 at 0x7efe715e4947
# 按Caller分组统计一下,看看各Caller各泄露的次数及内存量
$ mtrace malloc_trace.log | sed '1,/Caller/d'|awk