OutOfMemoryError (OOM)
如果项目报错: OutOfMemoryError: Java heap space,说明堆内存空间(Heap Space)中没有足够的空间来分配对象了。
一旦发生 OOM,系统有可能不可用,或者频繁重启。属于非常严重的问题。
OOM 的解决方法一:
比较简单粗暴的一种做法,是增大堆内存空间。
在 项目启动时,调大 -Xms 和 -Xmx 。
-Xms 参数用于设置JVM的初始堆内存大小,而-Xmx参数用于设置JVM的最大堆内存大小。
-Xms1024m -Xmx2048m
OOM 的解决方法二:
-Xms 和 -Xmx 哪怕调大了,如果没有找到根本的原因,大对象不断创建,不断地占用堆内存空间,还是有可能会继续 OOM。
可以设置在发生 OOM 时自动 dump 文件,保存到指定的文件。
dump文件是进程的内存镜像,可以通过分析 dump 文件,找到导致 OOM 的代码。
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=heapdump.hprof
oom 代码示例:
不断循环,不断创建对象,占用堆内存空间,模拟 OOM 的场景。
public class OomTest {
public static void main(String[] args) {
createObject();
}
/**
* 不断循环,不断创建对象,模拟 OOM 的场景
*
*/
public static void createObject() {
List<OomObject> oomList =new ArrayList<>();
while (true) {
OomObject oomObject = new OomObject();
oomList.add(oomObject);
}
}
}
添加 jvm 相关启动参数( Vm option ) :
-
点击 Edit Configurations:
-
点击 Modify options, 选择 Add Vm Options :
启动参数( Vm option ) 如下:
添加启动参数,设置最大内存为 8m,模拟 OOM 的场景。
HeapDumpOnOutOfMemoryError 表示在发生 OOM 时会自动 dump 。
-Xms4m -Xmx8m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:/heapdump.hprof
运行代码:
结果如下:
Connected to the target VM, address: '127.0.0.1:63909', transport: 'socket'
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/heapdump.hprof ...
Heap dump file created [31923817 bytes in 0.263 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at com.example.demo.oom.OomTest.createObject(OomTest.java:21)
at com.example.demo.oom.OomTest.main(OomTest.java:14)
可以看到 :
java.lang.OutOfMemoryError: Java heap space
Dumping heap to D:/heapdump.hprof …
这里的 D:/heapdump.hprof ,就是 dump 文件保存的路径。
打开 dump 文件
点击 Profiler ,再点击 Open Snapshot ,选择 上面的 dump 文件 D:/heapdump.hprof 。
点击 Biggest Objects, 可以看到 OomObject 这个对象占用了最大的内存。
结果如下:
使用 jdk 自带的 java visualvm ,分析dump文件, 找到 导致OOM 的代码
另外,也可以下载 MAT(Memory Analyzer Tool) 来分析 dump 文件。
此处使用 jdk 自带的 java visualvm 来分析 dump 文件, 找到 导致OOM 的代码 。
在 jdk 的 bin 文件中,找到 jvisualvm.exe 。点击即可运行。
- 装入 hprof 后缀的 dump 文件 :
打开 VisualVM 后,点击左上角的图标 ,装入, 文件名选择 之前的 dump 文件 D:/heapdump.hprof 。
文件类型 选择 【堆Dump(*.hprof)】。
可以看到,在出现 OutOfMemoryError 异常错误时进行了堆转储,导致 OutOfMemoryError 异常错误的线程 是哪一个。
点击这个线程,即可显示导致OOM的线程堆栈。
- 可以看到导致OOM的具体代码是类的哪一行: