一、溢出条件

Java堆用于存储对象实例,只要不断创建对象,并且保证GC Roots到对象之间有可达路径来保证垃圾回收机制无法回收这些空间,那么随着对象数量的增加,总容量触及到最大堆内存限制后,会触发OutOfMemoryError异常。

二、VM参数

-Xms20m //Java堆初始大小为20MB
-Xmx20m //Java堆最大大小为20MB,设置与初始值相同可避免内存扩展
-XX:+HeapDumpOnOutOfMemoryError //在堆内存溢出时进行堆内存转储,便于后续分析

三、演示代码

package OOM;

import java.util.ArrayList;
import java.util.List;

/**
 * VM Options: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
 */
public class HeapOOM {
    static class OOMObject{

    }

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

四、运行结果

java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid13548.hprof ...
Heap dump file created [28281635 bytes in 0.175 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 OOM.HeapOOM.main(HeapOOM.java:17)

五、jvisualvm.exe

jvisualvm.exe调试画面


类名 实例数(%) 实例数 大小
OOM.HeapOOM$OOMObject 99.01610258340277 810,326 (99%) 12,965,216 (64.1%)

通过jvisualvm可以快速定位问题所在

  1. 当出现内存泄露时,通过工具检查对象到GC Roots的引用链,找到泄露对象是通过怎样的引用路径、与哪些GC Roots相关联,才导致垃圾收集器无法回收他们。(根据对象的类型以及对象到GC Roots的引用链信息,一般可以准确定位到对象创建的位置)
  2. 当出现内存溢出时,适当调节对象的堆参数-Xms、-Xmx,并检查是否存在某些可以优化的对象(生命周期过长的、存储结构不合理的)
  3. 当dump出的堆转储文件特别小且发生OOM异常时,检查直接内存(Direct Memory)使用是否合理