深入JVM虛擬機之JVM可能會發生哪幾種OOM?如何進行排查和處理?

總覽:

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、需要大量經驗來判斷,儘可能對出現的場景做好總結

          

 

 
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章