通过dump文件,分析outOfMemoryError的排查过程和排查思路

1 篇文章 0 订阅
1 篇文章 0 订阅

前段时间发现有一个内存溢出导致java线上服务OOM的问题,通过jvm启动配置增加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/usr/local/app/oom的命令,在出现了第二次服务挂掉的时候,拿到了当时的dump文件,以下是我通过dump文件对异常进行梳理的过程。

首先,把服务器的dump文件拉到我本地后,使用jdk自带的jvisualvm装载dump文件

在载入后,我得到了各个类的内存占用情况分析图。如下:

在这个分析图表中,我发现到了byte[]、Long、string、char[]都占用了极大的空间,char[]和string都还好解释,毕竟string底层就是char[]数组,并且string在项目中经常被人使用,但是也没道理占用那么多空间。

经过仔细思考,我百思不得其解,于是我决定继续往下看看其他类对象的空间占用,这咋一看没什么问题,但是我突然警醒,有两个很重要的mysql下的对象byteArryRow和mysqlTextValueDecoder,居然实例数占到了800000左右如此之多。而且,再往下看,有一个业务对象performResultVo和这两个mysql对象实例数极为接近,突然嗅到了一股不一样的味道。

 当即,我跟踪了byteArryRow实例视图,突然发现,这个不就是结果集吗,用来把我们数据查询后的结果,遍历塞到我们的List里面。而且,这个byteArryRow不就是byte数组转换过来的吗,这个占用内存第一的byte[]不就挂勾上了吗。结合业务对象performResultVo和byteArryRow的实例数极其相近,我终于想通了,其实不就是byteArryRow在查询完数据后,将数据转为List<performResultVo>,而这个list的长度居然达到了800000条左右!!!

为了印证我的猜想是否正确,我跟踪了performResultVo的实例视图,发现了,这个类下面的字段,里面包含了大量string和4个Long对象。我将performResultVo实例数*4得到了3181392个实例数,再比对Long的实例数,发现实例数量基本一模一样。这也印证了我的猜想,就是因为出现了海量数据的查找,导致数据库查询出来的resultSet不断长时间循环赋值和内存空间创建,并且无法释放内存,导致内存被占满,最后溢出。

 这次通过dump排查OOM异常的经历终于圆满结束了,写在末尾,我想说一点儿心得。在出现内存溢出时,首先,必须要保证线上系统的立即可用;其次,要及时通过各类命令获得OOM的dump文件;然后,要仔细分析dump文件,找到他们内联的关系,不要错过任何一个疑惑的点,你想知道的,dump文件都可以告诉你;最后通过定位到的异常点,顺藤摸瓜,找到出错问题点,加以印证。

最后,贴一个OOM异常的所有报错情况,引用自怡安 - 博客园这位小伙伴的文章。

 

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值