OOM之GC Overhead limit exceeded

古城微笑少年丶 2023-06-20 06:23 115阅读 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

  1. package com.yq.gc;
  2. import java.util.ArrayList;
  3. import java.util.List;
  4. /** * Simple to Introduction代码非常简陋,只是为了说明问题 * className: HeapOOMDemo * -Xmx5m -Xms5m -XX:+HeapDumpOnOutOfMemoryError -XX:+PrintGCDateStamps -XX:+PrintGCDetails -Xloggc:gc.log * @author EricYang * @version 2019/8/7 14:54 */
  5. public class HeapOOMDemo {
  6. private static List<String> strList = new ArrayList<>();
  7. public static void main(String[] args) {
  8. int count = 10000;
  9. String str1 = "12345678901234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890";
  10. for(int i=0; i< count; i++) {
  11. strList.add(str1 + "i" + i);
  12. }
  13. System.out.println("...");
  14. for(int i=0; i< count; i++) {
  15. strList.add(str1 + "i" + i);
  16. strList.add(str1 + "i" + i);
  17. strList.add(str1 + "i" + i);
  18. }
  19. System.out.println("done");
  20. }
  21. }

运行结果

  1. java.lang.OutOfMemoryError: GC overhead limit exceeded
  2. Dumping heap to java_pid26720.hprof ...
  3. Heap dump file created [6397808 bytes in 0.026 secs]
  4. Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded
  5. at java.util.Arrays.copyOfRange(Arrays.java:3664)
  6. at java.lang.String.<init>(String.java:207)
  7. at java.lang.StringBuilder.toString(StringBuilder.java:407)
  8. at com.yq.gc.HeapOOMDemo.main(HeapOOMDemo.java:25)
  9. 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分析截图)
在这里插入图片描述

发表评论

表情:
评论列表 (有 0 条评论,115人围观)

还没有评论,来说两句吧...

相关阅读