记一次内存溢出(OOM)异常排查过程

932 阅读2分钟

曾经在生产环境中遇到过OOM异常,现在通过实践回顾一下当时的排查和处理思路。

1. 我有一张企业表有1200多万条数据。

1722394266592.png

2. 我在java程序中写一个接口查询全表数据

controller层

1722394310711.png

service层

1722394388820.png

dao层

1722394418449.png

mapper.xml

1722394471682.png

3. 将java程序打包上传至centos7.x服务器

通过mobaxterm打包上传即可。

4. 通过nohup java -jar命令运行jar包

为防止影响服务器上的其他应用,我指定JVM堆的大小为128MB,可以看到父进程号是:206168

1722394763784.png

5. postman调用接口

6. 查看centos服务器的变化,注意观察CPU变化

可以看到,调接口的一瞬间,服务器的206168进程的cpu已经飙升到了436.9% d091e1823b3440751ec7edf6a788d3d.png

7. 使用top -Hp pid 来查看2006168进程中具体的线程cpu占用情况

-H 线程模式 
-p 指定进程ID

8864582a9283b7fd0a1bc9e6c547b43.png 可以看到CPU占用率较高的都是GC线程

8. 找到进程中的具体占用CPU高的其中一个子进程

我们这里取206170线程id

9. 将线程id转为16进制

使用命令:printf "%x\n" 206170 1722395651357.png

  1. jstack -l 父进程的pid | grep 线程的pid(16进制),查看JVM日志在做什么?

1722396309621.png 发现这里是GC线程占用的CPU较高。

然后再看项目日志输出,发现也报了OOM异常

1722414058225.png

  1. jMap -histo 父进程pid | head -n 10 ,查看占用内存最多的十个对象

1722415457444.jpg 发现了一个业务实体类对象,创建的实例有一万八千多个,占用了3444112byte的空间。

  1. 找到了具体的业务对象,去业务当中具体排查。

根据CompanyAll16对象,去找引用到他,而且近期改动过的地方,发现是查了全表导致的OOM异常。 至此,OOM问题排查完毕