ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

深入理解 JVM 的 GC overhead limit exceeded 错误!

2021-03-22 22:52:09  阅读:308  来源: 互联网

标签:lang java 错误 overhead GC OutOfMemoryError limit


java 中有几个难兄难弟,比如我昨天写的 java.lang.OutOfMemoryError: Java heap space 和今天要写的 java.lang.OutOfMemoryError: GC overhead limit exceeded 等。要搞清这些知识,就需要深入的理解 JVM 底层原理和实现机制。

那么我们今天就具体来说说 java.lang.OutOfMemoryError: GC overhead limit exceeded 吧!

我们都知道,Java 语言的一大优势就是内存管理,也就是垃圾回收机制。相比其他语言,如:C++等,它们这些语言中并没有自动内存回收机制, 需要程序员手工编写代码来进行内存分配和释放, 以重复利用堆内存。

也正是因为 Java 语言有自动垃圾回收机制,所以一些程序员在使用不当的情况下,会发生一系列你意想不到的 OutOfMemoryError。关于 OutOfMemoryError 错误,目前一共有 8 种,我们一一的来搞定它们!

java.lang.OutOfMemoryError: GC overhead limit exceeded 这种情况发生的原因是程序基本上耗尽了所有的可用内存, GC 也清理不了。

更准确的说法应该是:执行垃圾收集的时间比例太大,有效的运算量太小。默认情况下,如果GC花费的时间超过 98%,并且GC 回收的内存少于 2%,JVM 就会抛出这个错误。

深入理解 JVM 的 GC overhead limit exceeded 错误!

java.lang.OutOfMemoryError: GC overhead limit exceeded 错误只在连续多次 GC 都只回收了不到2%的极端情况下才会抛出。假如不抛出 GC overhead limit 错误会发生什么情况呢? 那就是 GC 清理的这么点内存很快会再次填满,迫使 GC 再次执行。这样就形成恶性循环,CPU 使用率一直是 100%,而 GC 却没有任何成果。系统用户就会看到系统卡死。以前只需要几毫秒的操作,现在需要好几分钟才能完成。

下面我们来看一个产生“GC overhead limit exceeded” 错误的例子:

深入理解 JVM 的 GC overhead limit exceeded 错误!

为了能够更快的看到效果,我们可以设置一下 JVM 的参数:

深入理解 JVM 的 GC overhead limit exceeded 错误!

需要注意的是,不同的 GC 算法。产生的错误信息也不相同,有的可能会产生 java.lang.OutOfMemoryError: Java heap space 错误。

关于具体的 GC 算法,我给大家一张关于 Java8 GC 算法的列表,我后面再具体的写文章来讲。

深入理解 JVM 的 GC overhead limit exceeded 错误!
我们在说说上面产生 OutOfMemoryError 错误的代码吧。Map 在进行 rehash 时抛出了 java.lang.OutOfMemoryError 错误消息。如果使用其他垃圾收集算法,比如 -XX:+UseConcMarkSweepGC,或者 -XX:+UseG1GC,错误将被默认的 exception handler 所捕获,但是没有 stacktrace 信息,因为在创建 Exception 时没办法填充 stacktrace 信息。

再比如,有些厂商的 JVM 在 Win7x64,Java8 环境配置如下 UseG1GC:

深入理解 JVM 的 GC overhead limit exceeded 错误!

结果产生的错误信息却是:

深入理解 JVM 的 GC overhead limit exceeded 错误!

上面这些真实的案例表明,在资源受限的情况下,无法准确预测程序会死于哪种具体的原因。所以在这类错误面前,不能绑死某种特定的错误处理顺序。

有的人在解决 “java.lang.OutOfMemoryError: GC overhead limit exceeded” 错误时,配置了下面的启动参数:

我告诉你,这是一种完全错误的做法。因为 UseGCOverheadLimit 这样使用并不能真正地解决问题,只能推迟一点 out of memory 错误发生的时间,到最后还得进行其他处理。指定这个选项,会将原来的 java.lang.OutOfMemoryError: GC overhead limit exceeded 错误掩盖,变成更常见的 java.lang.OutOfMemoryError: Java heap space 错误消息。

有时候触发 GC overhead limit 错误的原因, 是因为分配给JVM的堆内存不足。这种情况下只需要增加堆内存大小即可。

在大多数情况下, 增加堆内存并不能解决问题。例如程序中存在内存泄漏, 增加堆内存只能推迟产生 java.lang.OutOfMemoryError: Java heap space 错误的时间。

所以,要想从根本上解决问题,则需要排查内存分配相关的代码。简单来说,需要搞清楚一下两点:

  • 哪类对象占用了最多内存?

  • 这些对象是在哪部分代码中分配的?

解决这类问题的流程和我上篇文章《为什么会产生 java.lang.OutOfMemoryError: Java heap space 错误以及如何解决?》中提到的流程一致。我就不再啰嗦了!

标签:lang,java,错误,overhead,GC,OutOfMemoryError,limit
来源: https://blog.51cto.com/15127565/2668867

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有