JVM实战 OutOfMemoryError Java堆溢出

我们都知道,JVM中三大区:堆区、栈区、方法区,其中堆区发生溢出的可能性尤其大,发生溢出大多是代码编写问题,我们现在就模拟一个Java堆溢出的场景。

代码如下:

import java.util.List;

public class HeapOOM {

    static class OOMObject {

    }

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();
        while(true) {
            list.add(new OOMObject());
        }
    }
}

运行代码之前,需要先修改JVM的参数配置,如下:

-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError

-Xms20m -Xmx20m 将堆最大最小内存都设置为20m

-XX:+HeapDumpOnOutOfMemoryError 是在虚拟机发生异常是,dump出当前内存信息,用于分析问题。

修改好JVM运行参数后,执行代码。

报错如下:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid17932.hprof ...
Heap dump file created [28214773 bytes in 0.053 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:265)
	at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231)
	at java.util.ArrayList.add(ArrayList.java:462)
	at com.itzhimei.study.jvm.HeapOOM.main(HeapOOM.java:16)

原因很明显,就是堆内存满了,后续新建的对象无法申请到内存空间,所以报了OutOfMemoryError的异常。

如果是平时,遇到这种情况我们可以用工具来分析异常发生时的dump文件,这里使用Memory Analyzer Tools来分析。

从图中可以看出,从根开始,往下有一个持有了大量对象的Objec,里面都是创建的OOMObject类的对象,就是我们代码里定义list所持有的。

这里还需要说明的两个点,就是图中列表里的Shallow Heap和Retained Heap

  1. Shallow Heap 表示当前对象占用的内存大小
  2. Retained Heap 表示当前对象及其能直接或间接访问到的对象,也就是发生垃圾回收时,能够释放的空间大小

内容学习自周志明老师的《深入理解Java虚拟机》