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
但是,如果實際應用程序代碼中存在內存泄漏,則這不能解決問題。相反,我們將推遲錯誤。因此,最好徹底重新評估應用程序的內存使用情況。