OOM内存溢出问题排查方法
在Java项目中,遇到 java.lang.OutOfMemoryError: GC overhead limit exceeded
异常时,通常意味着Java虚拟机(JVM)在进行垃圾回收时耗费了过多的时间,但释放的内存却非常有限。大概率就是因为内存泄漏,下面是一些排查和解决该问题的方法。
1. 手动导出内存快照
1.1. 导出堆内存快照
首先,我们需要获取当前Java进程的PID。可以使用以下命令:
jps -l
输出示例
12345 com.lcj.MainClass
在这个输出中:
12345
是进程的PID(进程ID)。com.lcj.MainClass
是正在运行的Java类的全名。
注意:如果您是在Docker容器中运行Java应用程序,请确保先进入容器,可以使用以下命令:
docker exec -it <container_id> /bin/bash
1.2. 使用 jmap
导出堆内存快照
找到PID后,使用以下命令导出堆内存快照:
jmap -dump:format=b,file=/dump.hprof 12345
这里的 /dump.hprof
是您希望保存堆快照的文件路径。
注意:如果是在Docker中,您需要将生成的快照从容器拷贝到宿主机。可以使用以下命令:
docker cp <container_id>:/dump.hprof /home/dump.hprof
2. 自动导出内存快照
2.1. 设置JVM启动参数
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dump.hprof
例如:
java -Xms750m -Xmx750m -Xmn512m -Xss1024k -XX:MaxPermSize=128m
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dump.hprof -Dfile.encoding=utf-8 -jar /data/app/test.jar
修改完记得重启,如果是docker环境,记得重建容器
3. 使用 VisualVM 分析堆快照
接下来,我们可以使用工具如 VisualVM 来分析堆快照。
如何查看对象
- 打开 VisualVM。
- 在左上角的open选项中打开刚刚导出的hprof快照文件。稍等一会它会加载完毕。
- 点击Summary旁边的小箭头切换到Objects,可以查看到当前内存快照中所有的对象及数量,点击根据数量count进行排序。
[]()
- 找到排名靠前的几个,查看除了JAVA的那些对象以外,是否有自己定义的业务对象。如果有且数量大,大概率就是有问题的,点击+可以看到持有的类文件名和行数。
[]()
- 此时应该去排查对应代码。检查问题,到这里问题就很容易发现了。
可能的原因
- 代码长时间未结束:函数内某些逻辑可能一直未结束,持续创建并持有该类型的对象,例如死循环等,且对象数量巨大,长时间持有大量对象引用,导致无法被GC。
- 静态变量:静态变量可能不断增加,导致内存占用持续上升无法GC。
文章评论