使用JProfiler分析和解决Java OOM问题
使用说明
发生OOM的情况一般都是因为程序中存在大对象,如果大对象存在是合理的,则说明程序需要的内存不足够。
而jprofiler就是一款可以根据dump信息检查程序OOM异常的软件。
jprofiler安装
idea插件搜索jprofiler安装,并去jprofiler官网下载软件:https://www.ej-technologies.com/products/jprofiler/overview.html
OK
解决思路
第一步:把jvm内存调大
VM options:
// 按倍调整
-Xms2048m -Xmx2048m
运行程序观察,如果在大内存下运行依然存在OOM问题,则说明是程序代码出现了问题。
第二步:定位OOM代码
调整对应的vm参数并dump出异常。
//把jvm内存调小,让程序提前OOM。 -Xms1m -Xmx4m -XX:+HeapDumpOnOutOfMemoryError
- 运行程序生成线程执行信息文件
使用了dump命令,当运行main方法后,除了在控制台输出Exception外还会在根项目
路径下生成一个java_pid.hprof
文件,里面保存了程序线程执行的内容。
- 运行程序生成线程执行信息文件
- 使用jprofiler分析
本地安装完成jprofiler软件后,可以直接双击打开项目根路径下的java_pidxx.hprof
文件即可。
我们需要关心的有:biggest objects和thread dump这两个主要信息。
- 使用jprofiler分析
biggest objects中我们可以知道项目存在哪些大对象,而从thread dump可以知道哪行代码发生了OOM(需要的就是这个)。
Dump命令可以捕获我们指定的error,只需要在-XX:
指定即可。
例子
编写一个让内存溢出的main线程程序,并在设置jvm参数后运行
/** * 设置堆内存溢出 */ public class OOMTest { public static void main(String[] args) { List list = new ArrayList<String>(); int count = 0; try{ while (true) { list.add(new OOMTest()); count += 1; } } catch (Error error) { System.out.printf("count= "+ count); } } }
在edit configurations中设置vm参数
-Xms1m -Xmx4m -XX:+HeapDumpOnOutOfMemoryError
- 运行程序,生成dump文件
可以看到count在while循环第106711次后发生了OOM,并生成了java_pid3652.hprof
文件。
- jprofiler使用
打开hprof文件后点击大对象可以看到一个很大的对象类型:ArrayList
- jprofiler使用
点击thread dump后选择我们运行的main线程可以看到,oom溢出定位到第15行代码中。(的确是发生在第15行)
over
还可以使用-XX:+PrintGCDetails
命令打印输出GC垃圾回收信息,查看gc回收的过程。