OutOfMemoryError: GC Overhead Limit Exceeded
1.概述
简而言之,当不再使用对象时,JVM 会负责释放内存;此过程称为垃圾回收 (Garbage Collection)(GC)。
The GC Overhead Limit Exceeded ERROR是来自 java.lang.OutOfMemoryError 系列错误中的一种,表示资源(内存)耗尽。
2.GC Overhead Limit Exceeded Error
OutOfMemoryError 是 java.lang.VirtualMachineError 的子类;当 JVM 遇到与利用资源相关的问题时,它会抛出。更具体地说,当 JVM 在执行垃圾回收时花费太多时间,并且只能回收很少的堆空间时,就会发生错误。
根据 Java 文档,默认情况下,如果 Java 进程花费超过 98% 的时间执行 GC,并且每次运行中仅恢复不到 2% 的堆,则 JVM 配置为引发此错误。换句话说,这意味着我们的应用程序已耗尽几乎所有可用的内存,并且垃圾回收器花费了太多时间尝试清理它,并反复失败。
在这种情况下,用户会遇到应用程序极其缓慢的情况。某些操作通常以毫秒为单位完成,需要更多时间才能完成。这是因为 CPU 正在使用其全部容量进行垃圾回收,因此无法执行任何其他任务。
3.举例
public class OutOfMemoryGCLimitExceed {
public static void addRandomDataToMap() {
Map<Integer, String> dataMap = new HashMap<>();
Random r = new Random();
while (true) {
dataMap.put(r.nextInt(), String.valueOf(r.nextInt()));
}
}
}
当调用此方法时,使用 JVM 参数为 -Xmx100m -XX:_UseParallelGC(Java堆大小设置为 100MB,GC 算法为 ParallelGC),我们得到一个 java.lang.outMemoryErrorError: GC Overhead Limit Exceeded error.。为了更好地理解不同的垃圾回收算法,我们可以查看 Oracle 的 Java 垃圾回收基础知识教程。
配置mvn exec:exec
我们能很快得到 java.lang.OutOfMemoryError: GC Overhead Limit Exceeded error 错误。
4.如何解决
理想的解决方案是通过检查代码以查找任何内存泄漏来查找应用程序的潜在问题。
需要解决以下问题:
-
应用程序中占据堆大部分的对象是什么?
-
这些对象在源代码的哪些部分被分配?
我们还可以使用自动图形工具,如 JConsole,它有助于检测代码中的性能问题,包括 java.lang.OutMemory 错误。
最后的手段是通过更改 JVM 启动配置来增加堆大小。例如,这为 Java 应用程序提供了 1GB 堆空间:
java -Xmx1024m com.xyz.TheClassName
但是,如果实际应用程序代码中存在内存泄漏,则这不能解决问题。相反,我们将推迟错误。因此,最好彻底重新评估应用程序的内存使用情况。