解Bug之路:记一次JVM堆外内存泄露Bug的查找

前言

JVM的堆外内存泄露的定位一直是个比较棘手的问题。此次的Bug查找从堆内内存的泄露反推出堆外内存,同时对物理内存的使用做了定量的分析,从而实锤了Bug的源头。

由于物理内存定量分析部分用到了linux kernel虚拟内存管理的知识,读者如果有兴趣了解请看ulk3(《深入理解linux内核第三版》)

内存泄露Bug现场

一个线上稳定运行了三年的系统,从物理机迁移到docker环境后,运行了一段时间,突然被监控系统发出了某些实例不可用的报警。所幸有负载均衡,可以自动下掉节点,如下图所示:

解Bug之路:记一次JVM堆外内存泄露Bug的查找

登录到对应机器上后,发现由于内存占用太大,触发OOM,然后被linux系统本身给kill了。

应急措施

紧急在出问题的实例上再次启动应用,启动后,内存占用正常,一切Okay。

奇怪现象

当前设置的最大堆内存是1792M,如下所示:

-Xmx1792m -Xms1792m -Xmn900m -XX:PermSize=256m -XX:MaxPermSize=256m -server -Xss512k

查看操作系统层面的监控,发现内存占用情况如下图所示:

解Bug之路:记一次JVM堆外内存泄露Bug的查找

上图蓝色的线表示总的内存使用量,发现一直涨到了4G后,超出了系统限制。

很明显,有堆外内存泄露了。

查找线索

gc日志

一般出现内存泄露,笔者立马想到的就是查看当时的gc日志。

本身应用所采用框架会定时打印出对应的gc日志,遂查看,发现gc日志一切正常。对应日志如下:

解Bug之路:记一次JVM堆外内存泄露Bug的查找

查看了当天的所有gc日志,发现内存始终会回落到170M左右,并无明显的增加。要知道JVM进程本身占用的内存可是接近4G(加上其它进程,例如日志进程就已经到4G了),进一步确认是堆外内存导致。

排查代码

打开线上服务对应对应代码,查了一圈,发现没有任何地方显式利用堆外内存,其没有依赖任何额外的native方法。关于网络IO的代码也是托管给Tomcat,很明显,作为一个全世界广泛流行的Web服务器,Tomcat不大可能有堆外内存泄露。

进一步查找

由于在代码层面没有发现堆外内存的痕迹,那就继续找些其它的信息,希望能发现蛛丝马迹。

Dump出JVM的Heap堆

由于线上出问题的Server已经被kill,还好有其它几台

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值