Excption與Error包結(jié)構(gòu),OOM,SOF

image.png

Java將可拋出(Throwable)的結(jié)構(gòu)分為三種類型:被檢查的異常(CheckedException),運行時異常(RuntimeException),錯誤(Error)。

1) 運行時異常

定義: RuntimeException及其子類都被稱為運行時異常。

特點: Java編譯器不會檢查它。也就是說,當(dāng)程序中可能出現(xiàn)這類異常時,倘若既"沒有通過throws聲明拋出它",也"沒有用try-catch語句捕獲它",還是會編譯通過。例如,除數(shù)為零時產(chǎn)生的ArithmeticException異常,數(shù)組越界時產(chǎn)生的IndexOutOfBoundsException異常,fail-fast機制產(chǎn)生的ConcurrentModificationException異常(java.util包下面的所有的集合類都是快速失敗的,“快速失敗”也就是fail-fast,它是Java集合的一種錯誤檢測機制。當(dāng)多個線程對集合進行結(jié)構(gòu)上的改變的操作時,有可能會產(chǎn)生fail-fast機制。記住是有可能,而不是一定。例如:假設(shè)存在兩個線程(線程1、線程2),線程1通過Iterator在遍歷集合A中的元素,在某個時候線程2修改了集合A的結(jié)構(gòu)(是結(jié)構(gòu)上面的修改,而不是簡單的修改集合元素的內(nèi)容),那么這個時候程序就會拋出 ConcurrentModificationException 異常,從而產(chǎn)生fail-fast機制,這個錯叫并發(fā)修改異常。Fail-safe,java.util.concurrent包下面的所有的類都是安全失敗的,在遍歷過程中,如果已經(jīng)遍歷的數(shù)組上的內(nèi)容變化了,迭代器不會拋出ConcurrentModificationException異常。如果未遍歷的數(shù)組上的內(nèi)容發(fā)生了變化,則有可能反映到迭代過程中。這就是ConcurrentHashMap迭代器弱一致的表現(xiàn)。ConcurrentHashMap的弱一致性主要是為了提升效率,是一致性與效率之間的一種權(quán)衡。要成為強一致性,就得到處使用鎖,甚至是全局鎖,這就與Hashtable和同步的HashMap一樣了。)等,都屬于運行時異常。

雖然Java編譯器不會檢查運行時異常,但是我們也可以通過throws進行聲明拋出,也可以通過try-catch對它進行捕獲處理。如果產(chǎn)生運行時異常,則需要通過修改代碼來進行避免。例如,若會發(fā)生除數(shù)為零的情況,則需要通過代碼避免該情況的發(fā)生!

2) 被檢查的異常

定義: Exception類本身,以及Exception的子類中除了"運行時異常"之外的其它子類都屬于被檢查異常。

特點 : Java編譯器會檢查它。 此類異常,要么通過throws進行聲明拋出,要么通過try-catch進行捕獲處理,否則不能通過編譯。例如,CloneNotSupportedException就屬于被檢查異常。當(dāng)通過clone()接口去克隆一個對象,而該對象對應(yīng)的類沒有實現(xiàn)Cloneable接口,就會拋出CloneNotSupportedException異常。被檢查異常通常都是可以恢復(fù)的。

被檢查的異常適用于那些不是因程序引起的錯誤情況,比如:讀取文件時文件不存在引發(fā)的FileNotFoundException。然而,不被檢查的異常通常都是由于糟糕的編程引起的,比如:在對象引用時沒有確保對象非空而引起的NullPointerException。

3) 錯誤

定義 : Error類及其子類。

特點 : 和運行時異常一樣,編譯器也不會對錯誤進行檢查。

當(dāng)資源不足、約束失敗、或是其它程序無法繼續(xù)運行的條件發(fā)生時,就產(chǎn)生錯誤。程序本身無法修復(fù)這些錯誤的。例如,VirtualMachineError就屬于錯誤。出現(xiàn)這種錯誤會導(dǎo)致程序終止運行。OutOfMemoryError、ThreadDeath。

Java虛擬機規(guī)范規(guī)定JVM的內(nèi)存分為了好幾塊,比如堆,棧,程序計數(shù)器,方法區(qū)等

OOM:

1,OutOfMemoryError異常

除了程序計數(shù)器外,虛擬機內(nèi)存的其他幾個運行時區(qū)域都有發(fā)生OutOfMemoryError(OOM)異常的可能。

Java Heap 溢出:

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

java堆用于存儲對象實例,我們只要不斷的創(chuàng)建對象,并且保證GC Roots到對象之間有可達(dá)路徑來避免垃圾回收機制清除這些對象,就會在對象數(shù)量達(dá)到最大堆容量限制后產(chǎn)生內(nèi)存溢出異常。

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

如果是內(nèi)存泄漏,可進一步通過工具查看泄漏對象到GCRoots的引用鏈。于是就能找到泄漏對象是通過怎樣的路徑與GC Roots相關(guān)聯(lián)并導(dǎo)致垃圾收集器無法自動回收。

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

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

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

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

這里需要注意當(dāng)棧的大小越大可分配的線程數(shù)就越少。

3,運行時常量池溢出

異常信息:java.lang.OutOfMemoryError:PermGenspace

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

4,方法區(qū)溢出

方法區(qū)用于存放Class的相關(guān)信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。也有可能是方法區(qū)中保存的class對象沒有被及時回收掉或者class信息占用的內(nèi)存超過了我們配置。

異常信息:java.lang.OutOfMemoryError:PermGenspace

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

SOF(堆棧溢出 StackOverflow):

StackOverflowError 的定義:當(dāng)應(yīng)用程序遞歸太深而發(fā)生堆棧溢出時,拋出該錯誤。

因為棧一般默認(rèn)為1-2m,一旦出現(xiàn)死循環(huán)或者是大量的遞歸調(diào)用,在不斷的壓棧過程中,造成棧容量超過1m而導(dǎo)致溢出。

棧溢出的原因:遞歸調(diào)用,大量循環(huán)或死循環(huán),全局變量是否過多,數(shù)組、List、map數(shù)據(jù)過大。

https://blog.csdn.net/qiuchaoxi/java/article/details/79788993

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時請結(jié)合常識與多方信息審慎甄別。
平臺聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點,簡書系信息發(fā)布平臺,僅提供信息存儲服務(wù)。

友情鏈接更多精彩內(nèi)容