当前位置: 代码迷 >> 综合 >> OOM之GC Overhead limit exceeded
  详细解决方案

OOM之GC Overhead limit exceeded

热度:67   发布时间:2024-01-05 08:57:26.0

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 exceededat 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

在这里插入图片描述

分析

官方的解释:
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分析截图)
在这里插入图片描述

  相关解决方案