关于内存泄露:使用mtrace追踪JVM堆外内存泄露
原创:扣钉日记(微信公众号ID:codelogs),欢送分享,非公众号转载保留此申明。简介在上篇文章中,介绍了应用tcmalloc或jemalloc定位native内存泄露的办法,但应用这个办法相当于更换了原生内存分配器,以至于应用时会有一些顾虑。 通过一些摸索,发现glibc自带的ptmalloc2分配器,也提供有追踪内存泄露的机制,即mtrace,这使得产生内存泄露时,可间接定位,而不须要额定装置及重启操作。 mtrace追踪内存泄露glibc中提供了mtrace这个函数来开启追踪内存调配的性能,开启后每次应用程序调用malloc或free函数时,会将内存调配开释操作记录在MALLOC_TRACE环境变量所指的文件外面,如下: $ pid=`pgrep java`# 配置gdb不调试信号,防止JVM收到信号后被gdb暂停$ cat <<"EOF" > ~/.gdbinithandle all nostop noprint passhandle SIGINT stop print nopassEOF# 设置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 -nMemory not freed:----------------- Address Size Caller0x00007efe08008cc0 0x18 at 0x7efe726e8e5d0x00007efe08008ea0 0x160 at 0x7efe726e8e5d0x00007efe6cabca40 0x58 at 0x7efe715dc4320x00007efe6caa9ad0 0x1bf8 at 0x7efe715e4b880x00007efe6caab6d0 0x1bf8 at 0x7efe715e4b880x00007efe6ca679c0 0x8000 at 0x7efe715e4947# 按Caller分组统计一下,看看各Caller各泄露的次数及内存量$ mtrace malloc_trace.log | sed '1,/Caller/d'|awk '{s[$NF]+=strtonum($2);n[$NF]++;}END{for(k in s){print k,n[k],s[k]}}'|column -t0x7efe715e4b88 1010 72316000x7efe715dc432 1010 888800x7efe715e4947 997 326696960x7efe726e8e5d 532 3098000x7efe715eb2f4 1 720x7efe715eb491 1 38能够发现,0x7efe715e4b88这个调用点,泄露了1010次,那怎么晓得这个调用点在哪个函数里呢? ...