一次OutOfMemoryError: GC overhead limit exceeded
現(xiàn)象:
由于需要將mysql表中的過期數(shù)據(jù)在凌晨定時讀取出過濾后轉(zhuǎn)入到MongoDB,一個轉(zhuǎn)換SQL達(dá)到百行,而且有幾十個,集中運行后程序反饋異常:
Handler dispatch failed; nested exception is java.lang.OutOfMemoryError: GC overhead limit exceeded
Heap內(nèi)存:1.5G,程序在Docker容器限制使用內(nèi)存2G。
監(jiān)控到內(nèi)存GC變化:
Heap內(nèi)存占用驟升至1.2G,然后不停的進(jìn)行FullGC,而且間隔非常短,從下圖中可以看出PermGen穩(wěn)定,這也表明讀取的數(shù)據(jù)由于太大是直接進(jìn)入了老年代內(nèi)存。
這時候CPU也彪升接近100%
請求訪問時長也加長,異常反饋。
java.lang.OutOfMemoryError: GC overhead limit exceeded 這種情況發(fā)生的原因是程序基本上耗盡了所有的可用內(nèi)存, GC 也清理不了。
更準(zhǔn)確的說法應(yīng)該是:執(zhí)行垃圾收集的時間比例太大,有效的運算量太小。默認(rèn)情況下,如果GC花費的時間超過 98%,并且GC 回收的內(nèi)存少于 2%,JVM 就會拋出這個錯誤。
網(wǎng)友的解決建議:
有的人在解決 “java.lang.OutOfMemoryError: GC overhead limit exceeded” 錯誤時,配置了下面的啟動參數(shù):
// 不推薦
-XX:-UseGCOverheadLimit
我告訴你,這是一種完全錯誤的做法。因為 UseGCOverheadLimit?這樣使用并不能真正地解決問題,只能推遲一點 out of memory 錯誤發(fā)生的時間,到最后還得進(jìn)行其他處理。指定這個選項,會將原來的 java.lang.OutOfMemoryError: GC overhead limit exceeded 錯誤掩蓋,變成更常見的 java.lang.OutOfMemoryError: Java heap space 錯誤消息。
有時候觸發(fā) GC overhead limit 錯誤的原因, 是因為分配給JVM的堆內(nèi)存不足。這種情況下只需要增加堆內(nèi)存大小即可。
在大多數(shù)情況下, 增加堆內(nèi)存并不能解決問題。例如程序中存在內(nèi)存泄漏, 增加堆內(nèi)存只能推遲產(chǎn)生 java.lang.OutOfMemoryError: Java heap space 錯誤的時間。
所以,要想從根本上解決問題,則需要排查內(nèi)存分配相關(guān)的代碼。簡單來說,需要搞清楚一下兩點:
- 哪類對象占用了最多內(nèi)存?
- 這些對象是在哪部分代碼中分配的?
總結(jié)
以上是生活随笔為你收集整理的一次OutOfMemoryError: GC overhead limit exceeded的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 使用Golang搭建gRPC服务提供给.
- 下一篇: 好奇!仅 13kB 大小的游戏,源码长啥