OOM之GC Overhead limit exceeded

Java8常见的OOM主要有三种,分别是Exception in thread thread_name: java.lang.OutOfMemoryError: Java heap space、Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceeded 以及Exception in thread thread_name: java.lang.OutOfMemoryError: Metaspace, 今天我们就重新其中的 GC Overhead limit exceeded,并借助gc log分析一下原因。

官方文档:https://docs.oracle.com/javase/8/docs/technotes/guides/troubleshoot/memleaks002.html#CIHHJDJE

重现

重新代码, 需要在启动参数加上-Xmx5m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:gc.log

package com.yq.gc;

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

/**
 * Simple to Introduction代码非常简陋,只是为了说明问题
 * className: HeapOOMDemo
 *  -Xmx5m -Xms5m  -XX:+HeapDumpOnOutOfMemoryError   -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:gc.log
 * @author EricYang
 * @version 2019/8/7 14:54
 */
public class HeapOOMDemo {
    private static List<String> strList = new ArrayList<>();

    public static void main(String[] args) {
        int count = 10000;
        String str1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
        for(int i=0; i< count; i++) {
            strList.add(str1 + "i" + i);
        }
        System.out.println("...");

        for(int i=0; i< count; i++) {
            strList.add(str1 + "i" + i);
            strList.add(str1 + "i" + i);
            strList.add(str1 + "i" + i);
        }
        System.out.println("done");
    }
}

运行结果

java.lang.OutOfMemoryError: GC overhead limit exceeded
Dumping heap to java_pid26720.hprof ...
Heap dump file created [6397808 bytes in 0.026 secs]
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
	at java.util.Arrays.copyOfRange(Arrays.java:3664)
	at java.lang.String.<init>(String.java:207)
	at java.lang.StringBuilder.toString(StringBuilder.java:407)
	at com.yq.gc.HeapOOMDemo.main(HeapOOMDemo.java:25)

Process finished with exit code 1

OOM之GC Overhead limit exceeded_第1张图片

分析

官方的解释:
Exception in thread thread_name: java.lang.OutOfMemoryError: GC Overhead limit exceeded
Cause: The detail message “GC overhead limit exceeded” indicates that the garbage collector is running all the time and Java program is making very slow progress. After a garbage collection, if the Java process is spending more than approximately 98% of its time doing garbage collection and if it is recovering less than 2% of the heap and has been doing so far the last 5 (compile time constant) consecutive garbage collections, then a java.lang.OutOfMemoryError is thrown. This exception is typically thrown because the amount of live data barely fits into the Java heap having little free space for new allocations.
Action: Increase the heap size. The java.lang.OutOfMemoryError exception for GC Overhead limit exceeded can be turned off with the command line flag -XX:-UseGCOverheadLimit.

总结起来就是:gc一致在运行并且java程序运行很慢。Java进程过去5个连续gc过程中,花费了大约98%+的时间进行gc并且回收的空间小于堆大小的2%,
采取的措施:增加堆大小,, 可以通过-XX:-UseGCOverheadLimit.关闭该异常。

注意:我给的例子比较极端,实际中很可能出现同一个程序有时候是java.lang.OutOfMemoryError: GC overhead limit exceeded,有时候是java.lang.OutOfMemoryError: Java heap space。 具体处理办法都是,先分析threaddump文件,看看那个地方能优化代码,不要长期持有不用的对象,防止memory leak,同时可以增加heapsize,也可以根据具体情况调整gc算法(调整后一定要进行对比测试),但是一般不建议调整gc算法。

heapdump文件分析(MAT分析截图)
OOM之GC Overhead limit exceeded_第2张图片

你可能感兴趣的:(Java,java8,JVM)