金三银四跳槽季最常见的JAVA面试题跑不掉的一个基本就是有没有碰到OOM的情况,以及排查OOM的过程。

正好赶上生产环境某个微服务出现OOM,将排查过程列一下,给找工作的朋友们贡献一个案例

缘起

某个不太重要的系统忽然报警,系统CPU load较高持续了一段时间,正常情况下这台服务器偶尔也会load偏高,但很快会降下来。

过程

首先找运维上服务器TOP看了一下CPU偏高的进程,发现是一个不常用的微服务,检查了git log发现最近一次、多次上线只是一些简单的增删改查,不存在内存泄漏的上线代码。

然后在服务器执行jstat -gccause 进程ID 5s,发现full GC频繁(10s左右一次),基本不用看jstack之类就知道应该是OOM造成的(实际系统日志中也能看到OutOfMemoryError的异常,但因为不太重要的微服,所以未加报警)

因为所有微服务的启动命令中统一有增加-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=$1_dump.hprof,会在发生OOM时候自动转存内存镜像

从服务器拉了dump文件导入JProfiler后,根据下图步骤:

  1. 点击Biggest Objects

Biggest Objects

  1. 在占用最大的对象上右键选择Use Selected Objects

Use Selected Objects

  1. 在弹出的提示框中选择Use Selected Objects,注意Referens的下拉列表中选择Incoming references

Use Selected Objects

  1. 展开就可以看到结果

结果

溯源

根据内存泄漏的调用方法,分析代码后发现是一个小伙伴去年9月份的一段代码,导出数据时候用了一个while(true)的分页循环数据的逻辑,但最后没有page++

为啥半年多没出问题的原因就在于之前那部分数据没超过一页……