使用mtrace追踪JVM堆外内存泄露

本文介绍了如何使用glibc自带的mtrace功能追踪Java应用的堆外内存泄露,通过分析malloc_trace.log文件、查找指令地址对应的函数以及通过arthas的profiler获取Java调用栈,从而定位内存泄露的源头。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

原创:扣钉日记(微信公众号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,内容如下:
image_2023-09-23_20230923162642
可以发现,在开启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 
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值