Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded

OutOfMemoryError,大家都知道是内存溢出了,那么GC overhead limit exceeded又是什么意思呢?

GC overhead limit exceeded
这是JDK6新增的错误类型,当GC占用大量时间释放很小空间时就会抛出这个异常,是JDK自身的一种保护机制。

GC overhead limt exceed检查是通过统计GC时间来预测是否需要OOM。
Sun 官方对此的定义是:”并行/并发回收器在GC回收时间过长时会抛出OutOfMemroyError。过长的定义是,超过98%的时间用来做GC并且回收了不到2%的堆内存。用来避免内存过小造成应用不能正常工作”。

下面的代码可以模拟GC overhead limit exceeded

public class ConstantPoolOOMTest {

    /**
     * VM Args:-XX:PermSize=5m -XX:MaxPermSize=5m
     * @param args
     */
    public static void main(String[] args) {
        List list = new ArrayList<>();
        int i=1;
        try {
            while(true){
                list.add(UUID.randomUUID().toString());
                i++;
            }
        } finally {
            System.out.println("运行次数:"+i);
        }
    }
}

运行结果:
运行次数:57241
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
    at java.lang.Long.toUnsignedString(Unknown Source)
    at java.lang.Long.toHexString(Unknown Source)
    at java.util.UUID.digits(Unknown Source)
    at java.util.UUID.toString(Unknown Source)
    at com.ghs.test.ConstantPoolOOMTest.main(ConstantPoolOOMTest.java:18)

上面说了,GC overhead limit exceeded 是JDK的一种保护机制,当你不需要这种保护机制时,可以通过添加下面的参数去掉这种保护机制。
-XX:-UseGCOverheadLimit
我们添加-XX:-UseGCOverheadLimit后,再运行上面的代码,结果可想而知,应该会抛出堆内存溢出异常。
那到底是不是呢?请看下面的运行结果

运行次数:58162
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
    at java.lang.Long.toUnsignedString(Unknown Source)
    at java.lang.Long.toHexString(Unknown Source)
    at java.util.UUID.digits(Unknown Source)
    at java.util.UUID.toString(Unknown Source)
    at com.ghs.test.ConstantPoolOOMTest.main(ConstantPoolOOMTest.java:18)

读到这里,你可能会想,JDK千方百计设计出这个策略,到底有什么用呢?即使你catch了这个异常,似乎也并不能拯救你的应用,但是在应用挂掉之前,你可以做垂死挣扎,比如数据保存或者保存现场(Heap Dump)。

你可能感兴趣的:(JVM)