Excption與Error包結構。OOM你遇到過哪些情況,SOF你遇到過哪些情況

一道很經典的Java開發面試題,答案寫的很全面,大部分內容都來自《深入理解Java虛擬機--JVM高級特性與最佳實踐》,很推薦大家看這本書,在看這本書的時候,讚歎作者的寫作功底,深入淺出!但是很多一開始看這本書的人感覺並不知道在講什麼,很推薦大家在看書的同時,多多上網查資料,看看網友們的總結,多多實踐!會幫助你理解JVM.

原文地址:http://www.mamicode.com/info-detail-1091344.html

Java異常架構圖

技術分享

1. Throwable 
Throwable是 Java 語言中所有錯誤或異常的超類。 
Throwable包含兩個子類: Error 和 Exception 。它們通常用於指示發生了異常情況。 
Throwable包含了其線程創建時線程執行堆棧的快照,它提供了printStackTrace()等接口用於獲取堆棧跟蹤數據等信息。

2. Exception 
Exception及其子類是 Throwable 的一種形式,它指出了合理的應用程序想要捕獲的條件。

3. RuntimeException 
RuntimeException是那些可能在 Java 虛擬機正常運行期間拋出的異常的超類。 
編譯器不會檢查RuntimeException異常。 例如,除數爲零時,拋出ArithmeticException異常。RuntimeException是ArithmeticException的超類。當代碼發生除數爲零的情況時,倘若既"沒有通過throws聲明拋出ArithmeticException異常",也"沒有通過try...catch...處理該異常",也能通過編譯。這就是我們所說的"編譯器不會檢查RuntimeException異常"! 
如果代碼會產生RuntimeException異常,則需要通過修改代碼進行避免。 例如,若會發生除數爲零的情況,則需要通過代碼避免該情況的發生!

4. Error 
和Exception一樣, Error也是Throwable的子類。 它用於指示合理的應用程序不應該試圖捕獲的嚴重問題,大多數這樣的錯誤都是異常條件。 
和RuntimeException一樣, 編譯器也不會檢查Error。

Java將可拋出(Throwable)的結構分爲三種類型: 被檢查的異常(Checked Exception),運行時異常(RuntimeException)和錯誤(Error)。

(01) 運行時異常 
定義 : RuntimeException及其子類都被稱爲運行時異常。 
特點 : Java編譯器不會檢查它。 也就是說,當程序中可能出現這類異常時,倘若既"沒有通過throws聲明拋出它",也"沒有用try-catch語句捕獲它",還是會編譯通過。例如,除數爲零時產生的ArithmeticException異常,數組越界時產生的IndexOutOfBoundsException異常,fail-fail機制產生的ConcurrentModificationException異常等,都屬於運行時異常。 
雖然Java編譯器不會檢查運行時異常,但是我們也可以通過throws進行聲明拋出,也可以通過try-catch對它進行捕獲處理。 
如果產生運行時異常,則需要通過修改代碼來進行避免。 例如,若會發生除數爲零的情況,則需要通過代碼避免該情況的發生!

(02) 被檢查的異常 
定義 :  Exception類本身,以及Exception的子類中除了"運行時異常"之外的其它子類都屬於被檢查異常。 
特點 : Java編譯器會檢查它。 此類異常,要麼通過throws進行聲明拋出,要麼通過try-catch進行捕獲處理,否則不能通過編譯。例如,CloneNotSupportedException就屬於被檢查異常。當通過clone()接口去克隆一個對象,而該對象對應的類沒有實現Cloneable接口,就會拋出CloneNotSupportedException異常。 
被檢查異常通常都是可以恢復的。

(03) 錯誤 
定義 : Error類及其子類。 
特點 : 和運行時異常一樣,編譯器也不會對錯誤進行檢查。 
當資源不足、約束失敗、或是其它程序無法繼續運行的條件發生時,就產生錯誤。程序本身無法修復這些錯誤的。例如,VirtualMachineError就屬於錯誤。 
按照Java慣例,我們是不應該是實現任何新的Error子類的!

對於上面的3種結構,我們在拋出異常或錯誤時,到底該哪一種?《Effective Java》中給出的建議是: 對於可以恢復的條件使用被檢查異常,對於程序錯誤使用運行時異常。

 

OOM:

1,   OutOfMemoryError異常

除了程序計數器外,虛擬機內存的其他幾個運行時區域都有發生OutOfMemoryError(OOM)異常的可能,

Java Heap 溢出

一般的異常信息:java.lang.OutOfMemoryError:Java heap spacess

java堆用於存儲對象實例,我們只要不斷的創建對象,並且保證GC Roots到對象之間有可達路徑來避免垃圾回收機制清除這些對象,就會在對象數量達到最大堆容量限制後產生內存溢出異常。

出現這種異常,一般手段是先通過內存映像分析工具(如Eclipse Memory Analyzer)對dump出來的堆轉存快照進行分析,重點是確認內存中的對象是否是必要的,先分清是因爲內存泄漏(Memory Leak)還是內存溢出(Memory Overflow)。

如果是內存泄漏,可進一步通過工具查看泄漏對象到GC Roots的引用鏈。於是就能找到泄漏對象時通過怎樣的路徑與GC Roots相關聯並導致垃圾收集器無法自動回收。

如果不存在泄漏,那就應該檢查虛擬機的參數(-Xmx與-Xms)的設置是否適當。

2,   虛擬機棧和本地方法棧溢出

如果線程請求的棧深度大於虛擬機所允許的最大深度,將拋出StackOverflowError異常。

如果虛擬機在擴展棧時無法申請到足夠的內存空間,則拋出OutOfMemoryError異常

這裏需要注意當棧的大小越大可分配的線程數就越少。

3,   運行時常量池溢出

異常信息:java.lang.OutOfMemoryError:PermGen space

如果要向運行時常量池中添加內容,最簡單的做法就是使用String.intern()這個Native方法。該方法的作用是:如果池中已經包含一個等於此String的字符串,則返回代表池中這個字符串的String對象;否則,將此String對象包含的字符串添加到常量池中,並且返回此String對象的引用。由於常量池分配在方法區內,我們可以通過-XX:PermSize和-XX:MaxPermSize限制方法區的大小,從而間接限制其中常量池的容量。

4,   方法區溢出

方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。

異常信息:java.lang.OutOfMemoryError:PermGen space

方法區溢出也是一種常見的內存溢出異常,一個類如果要被垃圾收集器回收,判定條件是很苛刻的。在經常動態生成大量Class的應用中,要特別注意這點。

 


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