如何修復Java中的VirtualMachineError

Java菜分享發表於2019-01-28

即使是最好的程式碼也會丟擲錯誤,對開發人員而言這意味著需要知道如何修復它們。在這篇文章中,Ram Lakshmanan 介紹了許多不同型別的 VirtualMachineError 以及如何解決這些問題,在應用程式不崩潰的前提下回到正常狀態。


當 Java 虛擬機器遇到內部錯誤或資源限制無法執行時,就會丟擲 Java.lang.VirtualMachineError。它是 JVM 的一種自我防禦機制,用於防止整個應用程式崩潰。 在本文中,我將討論許多不同型別的 VirtualMachineError,它們各自的特點、各種觸發原因、以及幾種可能的修復方案。

1. VirtualMachineError 的型別


有四種不同型別的 VirtualMachineError:


  1. OutOfMemoryError

  2. StackOverflowError

  3. InternalError

  4. UnknownError


讓我們在本節中詳細回顧這些型別。


如何修復Java中的VirtualMachineError

Java throwable 類層次結構


1.1 OutOfMemoryError


就像 OMG(Oh My God)的首字母縮寫一樣,OOM(OutOfMemoryError)在 DevOps 社群中非常流行。 雖然大多數 DevOps 的工程師可能認為只有一種 OutOfMemoryError,但實際上 OutOfMemoryError 有八種不同型別:


  • java.lang.OutOfMemoryError:Java 堆空間

  • java.lang.OutOfMemoryError:GC 開銷超過限制

  • java.lang.OutOfMemoryError:請求的陣列大小超過虛擬機器限制

  • java.lang.OutOfMemoryError:Permgen 空間

  • java.lang.OutOfMemoryError:Metaspace

  • java.lang.OutOfMemoryError:無法新建本機執行緒

  • java.lang.OutOfMemoryError:殺死程式或子進

  • java.lang.OutOfMemoryError:發生 stack_trace_with_native_method


觸發每種錯誤的原因各有不同。類似地,根據 OutOfMemoryError 不同的問題型別,對應的解決方案也不一樣。這裡有一份很好的文件,用一頁紙總結了所有不同型別的 OutOfMemoryError、觸發原因和解決方案。


通常可以通過分析垃圾回收日誌和堆轉儲檔案來診斷和修復 OutOfMemoryError 錯誤。手動分析垃圾回收日誌可能會很乏味,可以考慮使用免費工具,如 GCeasy、HP Jmeter 或 IBM GC analyzer。 類似地,也可以考慮使用 HeapHero 或 Eclipse MAT 這樣的免費工具來分析堆轉儲檔案。


參見:StackOverFlowError:原因及解決方案

1.2 StackOverflowError


執行緒的堆疊儲存了執行的方法、基本資料型別值、區域性變數、物件指標和返回值資訊,所有這些都會消耗記憶體。如果執行緒的堆疊大小超過了記憶體分配限制,那麼就會丟擲 java.lang.StackOverflowError。通常由於執行程式中有一個錯誤,線上程重複遞迴呼叫同一個函式時會發生這個問題。關於如何除錯 StackOverflowError 的細節以及修復這個問題可能的解決方案,更多資訊可以看這裡。


1.3 InternalError


JVM 丟擲 java.lang.InternalError 有三個原因,虛擬機器軟體出現錯誤、系統軟體底層出現錯誤或者硬體出現故障。


然而,很少會遇到 InternalError 這樣的錯誤。要了解哪些特定情況可能導致 InternalError,請在 Oracle 的 Java Bug 資料庫 中搜尋 InternalError。在寫這篇文章的時候(2018年12月20日),Oracle Java Bug 資料庫中僅報告了200個 InternalError,而且大多數都已經修復了,所以不必對此過於擔心。


1.4 UnknownError


當發生異常或錯誤,但 Java 虛擬機器無法報告確切的異常或錯誤時,就會丟擲 java.lang.UnknownError。UnknownError 很少出現。事實上,在 Oracle Java Bug 資料庫中搜尋 UnknownError 時,只找到了2個 Bug。


參見:遠端除錯 Java 應用程式

2. 特徵


VirtualMachineError 有兩個主要特徵:


  • 非受檢異常(Unchecked exceptions)

  • 同步模式與非同步模式


讓我們在本節中討論這兩個特徵。

2.1 非受檢異常


有兩種異常型別:受檢異常和非受檢異常。


在編譯時檢查的異常稱為受檢異常。如果程式碼中的某些方法丟擲受檢異常,那麼該方法必須處理該異常或者使用 throws 關鍵字指定異常。受檢異常包括 IOException、SQLException、DataAccessException、ClassNotFoundException 等。


非受檢異常常沒有這個要求,它們不需要捕獲或者宣告丟擲。所有型別的 VirtualMachineError 都是非受檢異常。


2.2 同步模式與非同步模式


可以在兩種模式下丟擲異常:同步模式和非同步模式。


同步異常在特定程式語句執行時發生,無論該程式在類似的環境中執行了多少次。同步異常的例子有 NullPointerException、 ArrayIndexOutOfBoundException 等。

非同步異常可以在任何時間點和程式語句的任何部分發生,異常丟擲的地方也不一樣。所有的 VirtualMachineError 都是非同步丟擲的,但有時也會同步丟擲。StackOverflowError 可能隨方法呼叫而同步丟擲,也可能隨著本地方法執行或 Java 虛擬機器資源限制非同步丟擲。類似地,OutOfMemoryError 可能在物件建立、陣列建立、類初始化和裝箱轉換時同步或非同步丟擲。

歡迎工作一到五年的Java工程師朋友們加入Java程式設計師開發: 854393687

 群內提供免費的Java架構學習資料(裡面有高可用、高併發、高效能及分散式、Jvm效能調優、Spring原始碼,MyBatis,Netty,Redis,Kafka,Mysql,Zookeeper,Tomcat,Docker,Dubbo,Nginx等多個知識點的架構資料)合理利用自己每一分每一秒的時間來學習提升自己,不要再用"沒有時間“來掩飾自己思想上的懶惰!趁年輕,使勁拼,給未來的自己一個交代! 


相關文章