记一次Java内存泄露导致的系统宕机

近期刚接手一个服务化应用,但每隔几天都会出现JVM进程僵死的情况。查看日志发现有大量的RocketMq Broker连接超时,起初怀疑是RocketMq broker不可用导致,但中间件同学反馈broker无异常。


应用异常日志

苦思无果后,使用jstack抓取JVM的线程堆栈,发现大量线程阻塞在获取RootLogger的锁


记一次Java内存泄露导致的系统宕机_第1张图片
image.png

而该锁又被另一个消费者线程持有,但该线程处于RUNNABLE状态,由此判断不是死锁问题。该线程当前持有的锁仅仅是写入本地日志,怀疑是日志写入存在瓶颈。然而查看磁盘的利用率和对应的日志文件的增长速度,又否定了该判断。


记一次Java内存泄露导致的系统宕机_第2张图片
image.png

随后使用jstat -gc指令分析JVM内存回收情况,发现老年代内存已经耗尽,FULL GC非常频繁,初步断定是JVM内存溢出。


image.png

使用jmap -histo指令发现业务对象OpenLogTO有350W未释放

记一次Java内存泄露导致的系统宕机_第3张图片
image.png

排查业务代码发现,该对象通过开源框架EventBus写入ConcurrentLinkedQueue,并由另外一个线程从队列中获取并消费,而消费者此时已经由于异常而退出,导致OpenLogTO持续通过EventBus写入队列而不会被消费。
排查线上的疑难杂症,除了需要剖根问底的精神,严谨的思考能力,还需要对JVM的调优工具比较熟悉。分享一篇 JVM性能调优工具使用 帮助大家了解JVM的常用调优工具。
记一次Java内存泄露导致的系统宕机_第4张图片
image.png

你可能感兴趣的:(记一次Java内存泄露导致的系统宕机)