1.问题定位
预发环境机器出现访问502的问题。
登录机器查看日志,没有发现特别的日志。
考虑到QA刚刚在做压测,想到是不是出现了OOM问题。搜索错误日志:
cat error.log | grep "OutOf"
果然有OOM错误日志:
java.lang.OutOfMemoryError: GC overhead limit exceeded
java.lang.OutOfMemoryError: GC overhead limit exceeded
锁定是出现OOM问题。
2.查看PID
使用命令
jps -lvm
列出当前机器所有运行中的JVM进程。找到Web服务对应的进程,拿到你进程ID。
3.查看堆信息
jmpa -heap 1207
可以看到整个堆的最大值为1G,MaxHeapSize 1024M。其中老年代683,年轻代340。整体配置偏小,接下来就是确定是由于配置的内存偏小,导致的OOM,还是有其他内存泄漏导致的。
4.查看是哪些对象占用了内存
使用jmap -histo PID命令查看堆中对象的占比。
jmap -histo 1207
因为对象种类一般来说较多,可以将上述命令的输出存入文件,方便后续查看。
jmap -histo 1207 > obj.txt
之后可以使用less等命令查看:
less obj.txt
输出结果中instances表示对象个数,bytes表示占用内存的字节数。其中最多的是[C,这个[表示的数组的意思。C表示char,合起来就是字符数组char[],字符串String底层使用字符数组存储,这个一般说明有大量的字符串。不过这也说明不了啥,一般项目都是字符串较多。
另外看到数量较多有HashMap的Node节点。这个自然就是HashMap,这个需要查一下看是哪块逻辑在用。项目用了Caffine缓存看了底层是ConcurrentHashMap存储的,不知道这么多HashMap是做什么的?
有3万多个HashMap不知道是干啥的?
5.使用MAT进行一步分析堆转储文件
上一步使用jmap -dump:live生成了堆转储文件,但是只能看到对象的数量和占用空间大小。对于HashMap、String等Java对象并不知道具体和什么业务相关。为了进一步分析还需要使用MAT。
https://blog.csdn.net/weixin_39850150/article/details/111250003
没有MAT时,也可以用jhat进行分析。
jhat为java自动的堆转储文件分析工具,特点是使用简单,不需要额外安装。
使用如下命令启动jhat
jhat dump.bin
其中dump.bin为堆转储文件。之后会启动一个http服务来查看分析结果,访问localhost:7000来进行查看。
默认进来展示了所有非Java原生类的情况,页面拉到最下面还有其他的页面可以查看:
6.分析结果
分析发现没有内存泄漏,单纯是内存设置过小导致的OOM。使用-Xmx6g 设置最大堆内存为6g,使用-Xms6g设置堆最小内存为6g,即进程启动后直接申请6g的内存使用。使用-Xmn2g设置年轻代大小为2g。