前言
记录一次线上JVM堆外内存泄漏问题的排查过程与思路,其中夹带一些常用的JVM问题排查指令和工具分享,希望能为大家带来帮助。
故障发生和描述
今天早上刚上班,运维那边钉钉发消息给我说昨晚服务器CPU负载太高,且发生报错。
叫他把日志拉取下来,一看…这不就是大名鼎鼎的OOM(内存溢出)吗?
头顶不断冒出 经验+1 经验+1...
默默的看了一眼眼前的《深入理解Java 虚拟机》,我枯了…终于派上用场了。我等你等的好辛苦…
其实昨晚就有迹象了,监控服务异常的小美,连续群里轰炸,已经麻木了
说完了心(BUG)路(来)历(源)程,接下来就是找问题了。
既然是堆内存溢出那当然是看Dump内存文件了。分析一波(书上是这么说的)
真是机智。
先找运维拉dump文件再说,然后...600M我应该从哪着手?
文件发过来,已是十一点半了...嗯?十一点半,干饭时间,食为先
拿到文件后,当然需要软件来打开了。
推荐两个分析工具
1.JProfiler
2.Memory Analyzer Tool
最终我选了jprofiler,并且安装了IDEA插件,方便后续问题排查!
打开软件,打开下载的dump快照文件(注:软件支持的格式有限,如果自己的dump文件格式不对,先改为支持的格式)
头皮发麻...这么多从哪找?
找了一圈后我放弃了,毕竟太大了...600M,没有指定是发生异常才记录,那就是记录了全部的内存快照了,只能让运维下次更新重启的时候加上了。
最后我才想起来了,我还有日志文件,报错的代码行,和报错信息。
java.util.NoSuchElementException: No value present
面向百度编程开始...
看到了这位大佬的解答,我恍然大悟,赶紧找到报错的代码所在位置。
果然。
也就是当get的调用主体查询不到、为空时,就会报 No value present 异常问题。
我真是机智
小心翼翼的看了一下备注,还好不是自己写的。
最后,问题既然已经找到,那就解决问题了,把BUG改造一下!
最后
单独一个异常可能不会触发OOM,但是这个方法是查询列表的一个方法,每次查询都会循环调用N次。
然后晚上23:00,我们服务有定时任务也在执行,需要占用大量的内存,然后刚好那会有人在用系统,报错了还不停下,还不停的点...最终导致了OOM。