我们都知道,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
- Shallow Heap 表示当前对象占用的内存大小
- Retained Heap 表示当前对象及其能直接或间接访问到的对象,也就是发生垃圾回收时,能够释放的空间大小
内容学习自周志明老师的《深入理解Java虚拟机》