记一次内存溢出排查流程

框架:

        springboot2.1.3 + netty4.1.67 + activemq-client5.15.6

现象描述:

任务在运行时内存在不断升高,达到设置的-Xmx时,进程被kill。

排查流程:

        一、netty内存泄漏:

        首先第一个想到使用netty的ByteBuf未释放,导致内存泄漏,通过添加启动命令:-Dio.netty.leakDetection.level=PARANOID来定位未释放的ByteBuf。添加后发现没有任何异常输出,并不是netty导致。

        二、替换垃圾收集器:

        在任务被kill掉时,通过free -g 观察操作系统,发现内存并未被释放,依然被占用。所以怀疑是否因为垃圾收集器导致内存未归还给操作系统 ,通过命令:java -XX:+PrintCommandLineFlags -version查看默认垃圾收集器如下:

 默认使用UseParallelGC 即 Parallel Scavenge + Parallel Old。添加启动命令:-XX:+UseG1GC将垃圾收集器改为G1收集器。 修改后,发现内存还是在持续增长,但是任务被kill之后,内存即时释放了,还未解决根本问题。

        三、分析内存:

        在服务器上安装arthas,启动任务通过dashboard命令观察实时面板,通过观察发现任务启动后,内存一直在实时增长,频繁触发youngGc,FullGc次数一直为0。老年代内存在小幅度增长,每次刷新增长几十M。当老年代内存到达上限时,触发了几次FullGc,且时间较长,但是内存并未释放,进程被kill。由此可判断是因为某个对象一直持续生成,且一直有引用无法被回收导致内存溢出。

 

  

检查代码后,未发现代码中有未释放的对象,开始分析dump日志。

        四、分析dump.hprof

        启动任务,待运行一段时间内存增长之后,在arthas中使用命令: heapdump /home/arthas/dump.hprof,使用mat分析dump日志。

        1.选择leak Suspects,查看可能泄漏的对象。

        2.发现在org.apache.activemq.ActiveMQMessageConsumer中存在一个LinkedList占用了90%的内存。

        3.在下方Details信息里发现该对象名为deliveredMessages。

 

         4.在详细信息中也可以观察到,在dump时,该LinkedList已经存储了53万多个对象,由此可见,该容器里的对象未被remove导致一直存在引用,无法被垃圾回收。

         五、分析代码

        由于org.apache.activemq.ActiveMQMessageConsumer是activeMq-client jar包中的类,所以我们先进行debug排查,首先搜索所有使用该变量的地方,尤其是添加和删除的地方,打上断点,开始调试。

        1.第一次进入断点是在添加的地方,调用addFirst方法将MessageDispatch对象放入list中,根据堆栈信息发现是从receive方法中调用而来,即每次拉取数据都会调用该方法。

        2.分析这段代码,当if中this.isAutoAcknowledgeBatch()成立后就会往list中存入对象,继续追踪isAutoAcknowledgeBatch()方法。此方法逻辑较为简单,判断消费到的消息是否需要批量ack并且不是Queue类型。如果返回false就会往deliveredMessages中存入MessageDispatch。由此可判断deliveredMessages中存入的是需要ack的信息。

         3.查看session创建的地方,发现确实是设置批量自动ack。按道理来说,不应该再存入deliveredMessages中。

        4.继续追踪 createSession方法,发现在transacted=true时,acknowledgeMode会设为0,即手动ack。至此真相大白,每次消费到数据都需要手动ack,deliveredMessages中记录了需要ack的消息,但是由于自认为设置的是自动提交,代码中并未手动提交,导致deliveredMessages一直持续增长至内存溢出。

         5.因为任务中并未使用事务,所以将transacted改为false即可。上线后,内存正常了......        

        结尾:有时候内存溢出的不一定是自己写的代码,不要只盯着自己的代码看!

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值