天天看點

讓你徹底了解JVM記憶體溢出(OOM)的含義

       當你的線上應用遇到 java.lang.OutOfMemoryError: 

Java heap space 異常時,你的應用到底處于什麼狀态,到底該不該重新開機?什麼情況下應該重新開機,什麼情況下可以不重新開機,結論是看情況,今天我通過實踐向你證明。

情況一、

        如果是局部對象過大導緻的,那麼記憶體溢出,相應的線程棧會被銷毀,相應的局部對象也會被GC回收,jvm安然無恙可以繼續處理其他請求。這也說明了局部對象過大導緻的溢出隻會影響目前線程,當線程被銷毀後,記憶體很快被GC,不會影響其他線程。

#

讓你徹底了解JVM記憶體溢出(OOM)的含義

#

讓你徹底了解JVM記憶體溢出(OOM)的含義

如上圖可以看出,3次溢出後記憶體都能及時釋放,不影響其他線程,記憶體狀态完全正常,JVM可以流暢運作。

情況二、

        如果是靜态對象,或者共享對象,發生記憶體溢出後,不會得到釋放(GC不能回收根可達對象),所有線程基本上處于靜止狀态,運作非常慢,因為沒有記憶體啊,GC非常頻繁,不能處理任何請求(報 out of memory error ),dubbo與注冊中心也會失去聯系,用arthas大機率是attach失敗,用VisualVM能艱難的連上去,用jmap可以很輕松連上去。下面是第二種情況出現後的報錯情況,這說明記憶體不能釋放影響了其它線程的正常運作。影響了dubbo與注冊中心的聯系,注冊中心會将其删除。

#

讓你徹底了解JVM記憶體溢出(OOM)的含義

下面使用VisualVM艱難的連上去了,可以直覺的觀察下記憶體情況

看到dubbo相關的線程也受到影響,不能正常和注冊中心聯系了

#

讓你徹底了解JVM記憶體溢出(OOM)的含義

記憶體居高不下,無法釋放,線程反應遲鈍,因為GC在大量頻繁執行,這就會導緻大量的STW

#

讓你徹底了解JVM記憶體溢出(OOM)的含義

看到基本上每時每刻都在GC,這時候你的業務程式基本上處于停滞狀态。

這時用arthas根本連不上去,因為監聽線程都無法正常工作

#

讓你徹底了解JVM記憶體溢出(OOM)的含義
讓你徹底了解JVM記憶體溢出(OOM)的含義

#

總結

       當遇到情況1時,就不需要進行重新開機,但是要捕獲異常,發送告警資訊,開發人員通過觀察OOM線程棧日志,基本上能找到問題根源。

       當遇到情況2時,需要進行重新開機才能恢複正常,在這種情況下,由于頻繁的GC導緻大量STW,後續指令的執行會非常慢,非常困難,告警資訊都不一定能發出去,可能還是需要通過對日志的監控來發送告警資訊。比較欣慰的是這種情況下,也會導緻dubbo服務會和注冊中心失聯(任何線程執行都基本處于停滞狀态),進而相當于自動隔離了故障容器。開發人員介入後,在重新開機之前使用jmap指令保留下現場證據,便于排查問題(arthas和VisualVM基本上已經很難連接配接上去了)。