總覽:
1、當JVM內存嚴重不足時,會拋出java.lang.OutOfMemoryError:xxxx錯誤
2、根據實際生產經驗,OOM是非常嚴重的問題,一般會對程序日誌中的OutOfMemeoryError配置關鍵字告警,一經發現,立即處理。
Java Heap Space :
當堆內存沒有足夠的空間存放創建的對象時,就會拋出java.lang.OutOfMemoryError:Java heap space錯誤:
1、請求創建一個巨大對象,通常是一個大數組
2、超出預期的訪問量、數據量、比如流動飆升的促銷、秒殺活動
3、內存泄露(Memory Leak)的出現,大量對象引用沒有釋放,JVM無法對其自動回收,比如ThreadLocal、線程池無界隊列等
針對大部分情況,通常只需要通過 -Xmx參數調高JVM堆內存空間即可。如果仍然沒有解決,可以參考以下情況做進一步處理:
1、如果是超大對象,可以檢查其合理性,比如是否一次性查詢了數據庫全部結果,而沒有做結果數限制
2、如果是業務峯值壓力,可以考慮添加機器資源,或者做限流降級
GC overhead limit exceeded
1、話費超過98%的時間來做GC,但回收不到2%的堆內存,且該動作連續重複了5次,就會拋出java.lang.OutMemoryError:GC overhead limit exceed錯誤
2、簡單地說,就是應用程序已經基本耗盡了所有可用內存,GC也無法回收
3、JVM給出這樣一個參數: -XX:UserGCOverheadLimit 禁用這個檢查,其實這個參數解決不了內存問題,只是把錯誤的信息延後,替換成javalang.OutMememoryError:Java heap space
Permgen space
該錯誤表示永久代(Permanent Generation)已用滿,通常是因爲加載的class數目太多或體積太大
解決方案:
1、程序啓動報錯,修改 -XX:MaxPermSize 啓動參數,調大永久代空間
2、應用程序部署時報錯,很可能應用程序沒有重啓,導致加載了多封class信息,只需要重啓JVM即可解決。
3、運行時報錯,應用程序可能會動態創建大量class,而這些class的生命週期和短暫,但是JVM默認不會卸載class,可以設置 -XX:+CMSClassUnloadingEnabled和-XX:+UserMarkSweepGC這兩個參數允許JVM 卸載class
4、如果上述方法無法解決,可以通過 jmap 命令dump內存對象,逐一分析開銷最大的classloader和重複class
Metaspace
JDK8後使用元空間(Metaspace)替換了永久代(Permanent Generation),該錯誤表示Metaspace已被用滿,通常還是因爲加載的class數目太多或體積太大
Unable to creat new native thread
Java 線程(用戶線程)對應着操作系統的內核級線程
Java 線程的創建會通過JVM向底層操作系統請求創建一個新的native線程,如果沒有足夠的資源分配就會報此類錯誤
解決方案:
1、升級配置,爲機器提供更多的內存
2、修復應用程序的線程泄露問題
3、限制線程池大小
4、使用 -Xss參數減少線程棧的大小
Direct buffer memory
堆外內存一旦使用超過限制,就會拋出Direct buffer memoey錯誤
解決方案:
1、檢查是否直接或間接使用了NIO,如netty,jetty等
2、通過啓動參數 -XX:MaxDirectMemporySize調整Direct ByteBuffer的上限值
3、檢查JVM的參數值是否有 -XX:+DisableExolicitGC選項,如果有就去掉,因爲該參數會使System.gc()失效
總結:
1、OOM錯誤是非常嚴重的錯誤,線上出現時需要第一時間處理
2、需要大量經驗來判斷,儘可能對出現的場景做好總結