GC Overhead Limit Exceeded

2025年5月3日 | 阅读 6 分钟

当 Java 应用程序在垃圾回收上花费的时间超过平时,JVM 就会抛出“gc overhead limit exceeded”错误。这里的 GC 指的是“Garbage Collection”(垃圾回收)。但不必担心,因为该错误可以通过遵循一些要点快速解决。

在本节中,我们将讨论解决此错误的要点。我们还将了解 JVM 为什么会抛出此错误。我们将尝试通过一个例子来理解该错误。

“gc overhead limit exceeded”错误是什么

JVM 抛出的完整错误是“java.lang.OutOfMemoryError: gc overhead limit exceeded”。当 Java 应用程序花费 98% 的时间在垃圾回收上时,就会抛出此错误。此时,JVM 会向用户发出信号,表明您正在执行的应用程序在垃圾回收上花费了 98% 的时间;因此,总时间中只有不到 2% 的时间用于堆回收。JRE 具有内置的垃圾回收机制,Java 功能允许用户为 Java 应用程序分配内存,当内存中某些空间不再被使用时,GC 会为它们清理内存。因此,GC Overhead limit Exceeded 错误属于java.lang.OutOf MemoryError,这表示内存耗尽。

为什么会抛出“gc overhead limit exceeded”错误

如上所述,此错误属于OutOfMemory错误,这表明资源利用率正在耗尽,并且只回收了少量的堆空间。根据 Java 文档,可以读到,如果 Java 虚拟机发现 Java 进程花费了总时间的约 98% 在进行 GC,并且在连续 5 次垃圾回收中重复出现这种情况,则默认允许抛出此错误。因此,应用程序变得响应非常缓慢,因为 CPU 正忙于垃圾回收,而其他任务或操作则排队等待。此错误主要是因为应用程序能够放入堆中的可用实时数据非常少,因为可用于新分配的空间不足。

实践实现

为了理解这个概念,实践实现是解释它的好方法。让我们来看一个例子,我们创建了一个名为 GCOverheadlimitexceeded 的类,它定义了一个 ArrayList,并在一个未终止的循环中向列表中添加了新的 GCOverheadexceeded (),如下所示:

代码片段也显示在下方

GC Overhead Limit Exceeded

要执行上面的代码,请按照以下步骤操作:

  • 右键单击代码,选择“运行方式” > “运行配置”,然后会打开一个对话框,如下图所示:
GC Overhead Limit Exceeded
  • “参数”下,将“VM 参数”值设置为-Xmx100m -XX:+UseParallelGC,如果已设置,则跳过。然后单击“应用”**
GC Overhead Limit Exceeded
  • 首次执行时,在许多情况下会遇到lang.OutOfMemoryError: Java heap space错误。下面是快照:
GC Overhead Limit Exceeded
  • 因此,再次将其作为 Java 应用程序执行,现在您将遇到lang.OutOfMemoryError: gc overhead limit exceeded错误,如下图所示:
GC Overhead Limit Exceeded

GC 堆栈溢出限制错误的根本原因

由于以下可能的原因,JVM 会突然抛出 gc overhead limit exceeded 错误:

原因 1:我们的 Java 应用程序可能存在内存泄漏。

原因 2:如果我们修改了代码,而这些修改可能需要更多内存并倾向于在内存中存储更多对象,这会阻止 GC 清理堆内存。

为了验证这两种原因,我们需要检查以下内容:

  • 检查您是否有任何应用程序缓存并增加了其大小,但未相应地增加最大堆大小 (Xmx)。
  • 检查您是否创建了新的缓存或缓存数据结构来存储内存中的对象。

注意:应该知道,为了避免资源耗尽,请使用有界缓存,因为它限制了内存;而无界缓存可能会耗尽内存。

修复 GC 堆栈溢出限制错误

为了解决和修复给定代码的 gc overhead limit exceeded 错误,需要回答以下问题:

  • 代码中的哪些对象使用了大部分堆空间?
  • 这些对象分配到了源代码的哪个部分?

为了知道这些问题的答案,可以使用JConsole,它是一个自动化的图形工具,通过它可以检测代码中出现的性能问题,包括java.lang.OutOfMemory Errors。Jconsole 工具已包含在Java Development Kit中。除了内置工具外,还有其他内存分析工具,如 Visual VM 和 Eclipse MAT,可以从互联网下载。

1) 要使用 Jconsole 监控工具,请打开Windows 命令提示符并输入Jconsole命令,如下图所示:

GC Overhead Limit Exceeded

2) 如果可用,将打开Java 监控和管理控制台,如下图所示:

GC Overhead Limit Exceeded

3) 您可以通过从本地进程中选择 Java 程序名称来监控 Jconsole,或者如果您知道<主机名><端口>值,您可以选择远程进程。在这里,我们选择了本地进程选项,因为我们创建的 Java 程序名称在本地进程列表中可见,如上所示。

注意:如果您看不到您创建的程序名称,请转到 IDE 并运行该程序,然后再次在 cmd 中键入 Jconsole,现在您应该能在本地进程列表中看到程序名称。

单击连接

5) 在某些情况下,会弹出一个对话框;单击不安全的连接。否则,请跳过此步骤。下面是快照:

GC Overhead Limit Exceeded

最后,您将获得 Jconsole 连接窗口,正如我们为我们的代码获得的:

GC Overhead Limit Exceeded

之后,我们可以理解内存使用情况并执行以下任务:

  • 内存泄漏

要了解 Java 程序的内存泄漏,请单击内存选项卡,然后我们可以看到内存使用图表,如下图所示:

GC Overhead Limit Exceeded

在这里,您可以看到我们代码的内存使用情况,并且可以看到先是增加,然后减少。从这里,我们可以分析内存使用情况(堆内存使用情况)、总时间、已用内存、已提交内存和 GC 时间。

  • 分析线程

在内存选项卡旁边是线程选项卡,我们可以从中分析程序中使用的线程数,对于我们的程序,我们有以下图表:

GC Overhead Limit Exceeded
  • 类摘要

在线程选项卡旁边,我们有一个选项卡,它告诉我们为我们的程序创建的类,我们有以下图表:

GC Overhead Limit Exceeded
  • VM 摘要

此选项卡告诉我们代码的完整摘要,并且可以从这里分析占用最大堆空间的那些对象,如下图所示:

GC Overhead Limit Exceeded

因此,使用 Jconsole 或任何其他监控工具可以帮助您确定 GC 堆栈溢出限制错误的根本原因,并告诉您占用最高内存并导致此类错误的对象。