版權(quán)聲明:本文為博主原創(chuàng)文章,未經(jīng)博主允許不得轉(zhuǎn)載。
【情況一】:
Java.lang.OutOfMemoryError:Javaheap space:這種是java堆內(nèi)存不夠,一個(gè)原因是真不夠,另一個(gè)原因是程序中有死循環(huán);
如果是java堆內(nèi)存不夠的話,可以通過調(diào)整JVM下面的配置來解決:
< jvm-arg>-Xms3062m < / jvm-arg>
< jvm-arg>-Xmx3062m < / jvm-arg>
【情況二】
java.lang.OutOfMemoryError: GC overhead limit exceeded
【解釋】:JDK6新增錯(cuò)誤類型,當(dāng)GC為釋放很小空間占用大量時(shí)間時(shí)拋出;一般是因?yàn)槎烟。瑢?dǎo)致異常的原因,沒有足夠的內(nèi)存。
【解決方案】:
1、查看系統(tǒng)是否有使用大內(nèi)存的代碼或死循環(huán);
2、通過添加JVM配置,來限制使用內(nèi)存:
< jvm-arg>-XX:-UseGCOverheadLimit< /jvm-arg>
【情況三】:
java.lang.OutOfMemoryError: PermGen space:這種是P區(qū)內(nèi)存不夠,可通過調(diào)整JVM的配置:
< jvm-arg>-XX:MaxPermSize=128m< /jvm-arg>
< jvm-arg>-XXermSize=128m< /jvm-arg>
【注】:
JVM的Perm區(qū)主要用于存放Class和Meta信息的,Class在被Loader時(shí)就會(huì)被放到PermGen space,這個(gè)區(qū)域成為年老代,GC在主程序運(yùn)行期間不會(huì)對(duì)年老區(qū)進(jìn)行清理,默認(rèn)是64M大小,當(dāng)程序需要加載的對(duì)象比較多時(shí),超過64M就會(huì)報(bào)這部分內(nèi)存溢出了,需要加大內(nèi)存分配,一般128m足夠。
【情況四】:
java.lang.OutOfMemoryError: Direct buffer memory
調(diào)整-XX:MaxDirectMemorySize= 參數(shù),如添加JVM配置:
< jvm-arg>-XX:MaxDirectMemorySize=128m< /jvm-arg>
【情況五】:
java.lang.OutOfMemoryError: unable to create new native thread
【原因】:Stack空間不足以創(chuàng)建額外的線程,要么是創(chuàng)建的線程過多,要么是Stack空間確實(shí)小了。
【解決】:由于JVM沒有提供參數(shù)設(shè)置總的stack空間大小,但可以設(shè)置單個(gè)線程棧的大小;而系統(tǒng)的用戶空間一共是3G,除了Text/Data/BSS /MemoryMapping幾個(gè)段之外,Heap和Stack空間的總量有限,是此消彼長(zhǎng)的。因此遇到這個(gè)錯(cuò)誤,可以通過兩個(gè)途徑解決:
1.通過 -Xss啟動(dòng)參數(shù)減少單個(gè)線程棧大小,這樣便能開更多線程(當(dāng)然不能太小,太小會(huì)出現(xiàn)StackOverflowError);
2.通過-Xms -Xmx 兩參數(shù)減少Heap大小,將內(nèi)存讓給Stack(前提是保證Heap空間夠用)。
【情況六】:
java.lang.StackOverflowError
【原因】:這也內(nèi)存溢出錯(cuò)誤的一種,即線程棧的溢出,要么是方法調(diào)用層次過多(比如存在無限遞歸調(diào)用),要么是線程棧太小。
【解決】:優(yōu)化程序設(shè)計(jì),減少方法調(diào)用層次;調(diào)整-Xss參數(shù)增加線程棧大小。
Throwable
Throwable是 Java 語言中所有錯(cuò)誤或異常的超類。
Throwable包含兩個(gè)子類: Error 和 Exception 。它們通常用于指示發(fā)生了異常情況。
Throwable包含了其線程創(chuàng)建時(shí)線程執(zhí)行堆棧的快照,它提供了printStackTrace()等接口用于獲取堆棧跟蹤數(shù)據(jù)等信息。
Exception
Exception及其子類是 Throwable 的一種形式,它指出了合理的應(yīng)用程序想要捕獲的條件。
RuntimeException
RuntimeException是那些可能在 Java 虛擬機(jī)正常運(yùn)行期間拋出的異常的超類。
編譯器不會(huì)檢查RuntimeException異常。例如,除數(shù)為零時(shí),拋出ArithmeticException異常。RuntimeException是ArithmeticException的超類。當(dāng)代碼發(fā)生除數(shù)為零的情況時(shí),倘若既”沒有通過throws聲明拋出ArithmeticException異常”,也”沒有通過try…catch…處理該異常”,也能通過編譯。這就是我們所說的”編譯器不會(huì)檢查RuntimeException異常”!
如果代碼會(huì)產(chǎn)生RuntimeException異常,則需要通過修改代碼進(jìn)行避免。 例如,若會(huì)發(fā)生除數(shù)為零的情況,則需要通過代碼避免該情況的發(fā)生!
Error
和Exception一樣, Error也是Throwable的子類。 它用于指示合理的應(yīng)用程序不應(yīng)該試圖捕獲的嚴(yán)重問題,大多數(shù)這樣的錯(cuò)誤都是異常條件。
和RuntimeException一樣,編譯器也不會(huì)檢查Error。
Java將可拋出(Throwable)的結(jié)構(gòu)分為三種類型:被檢查的異常(Checked Exception),運(yùn)行時(shí)異常(RuntimeException)和錯(cuò)誤(Error)。
(01) 運(yùn)行時(shí)異常
定義 : RuntimeException及其子類都被稱為運(yùn)行時(shí)異常。
特點(diǎn) :Java編譯器不會(huì)檢查它。 也就是說,當(dāng)程序中可能出現(xiàn)這類異常時(shí),倘若既”沒有通過throws聲明拋出它”,也”沒有用try-catch語句捕獲它”,還是會(huì)編譯通過。例如,除數(shù)為零時(shí)產(chǎn)生的ArithmeticException異常,數(shù)組越界時(shí)產(chǎn)生的IndexOutOfBoundsException異常,fail-fail機(jī)制產(chǎn)生的ConcurrentModificationException異常等,都屬于運(yùn)行時(shí)異常。
雖然Java編譯器不會(huì)檢查運(yùn)行時(shí)異常,但是我們也可以通過throws進(jìn)行聲明拋出,也可以通過try-catch對(duì)它進(jìn)行捕獲處理。
如果產(chǎn)生運(yùn)行時(shí)異常,則需要通過修改代碼來進(jìn)行避免。 例如,若會(huì)發(fā)生除數(shù)為零的情況,則需要通過代碼避免該情況的發(fā)生!
(02) 被檢查的異常
定義 :? Exception類本身,以及Exception的子類中除了”運(yùn)行時(shí)異常”之外的其它子類都屬于被檢查異常。
特點(diǎn) :Java編譯器會(huì)檢查它。此類異常,要么通過throws進(jìn)行聲明拋出,要么通過try-catch進(jìn)行捕獲處理,否則不能通過編譯。例如,CloneNotSupportedException就屬于被檢查異常。當(dāng)通過clone()接口去克隆一個(gè)對(duì)象,而該對(duì)象對(duì)應(yīng)的類沒有實(shí)現(xiàn)Cloneable接口,就會(huì)拋出CloneNotSupportedException異常。
被檢查異常通常都是可以恢復(fù)的。
(03) 錯(cuò)誤
定義 : Error類及其子類。
特點(diǎn) : 和運(yùn)行時(shí)異常一樣,編譯器也不會(huì)對(duì)錯(cuò)誤進(jìn)行檢查。
當(dāng)資源不足、約束失敗、或是其它程序無法繼續(xù)運(yùn)行的條件發(fā)生時(shí),就產(chǎn)生錯(cuò)誤。程序本身無法修復(fù)這些錯(cuò)誤的。例如,VirtualMachineError就屬于錯(cuò)誤。
按照J(rèn)ava慣例,我們是不應(yīng)該是實(shí)現(xiàn)任何新的Error子類的!
對(duì)于上面的3種結(jié)構(gòu),我們?cè)趻伋霎惓;蝈e(cuò)誤時(shí),到底該哪一種?《Effective Java》中給出的建議是:對(duì)于可以恢復(fù)的條件使用被檢查異常,對(duì)于程序錯(cuò)誤使用運(yùn)行時(shí)異常。
1,? OutOfMemoryError異常
除了程序計(jì)數(shù)器外,虛擬機(jī)內(nèi)存的其他幾個(gè)運(yùn)行時(shí)區(qū)域都有發(fā)生OutOfMemoryError(OOM)異常的可能,
javaHeap 溢出
一般的異常信息:java.lang.OutOfMemoryError:Java heap spacess
java堆用于存儲(chǔ)對(duì)象實(shí)例,我們只要不斷的創(chuàng)建對(duì)象,并且保證GC Roots到對(duì)象之間有可達(dá)路徑來避免垃圾回收機(jī)制清除這些對(duì)象,就會(huì)在對(duì)象數(shù)量達(dá)到最大堆容量限制后產(chǎn)生內(nèi)存溢出異常。
出現(xiàn)這種異常,一般手段是先通過內(nèi)存映像分析工具(如Eclipse Memory
Analyzer)對(duì)dump出來的堆轉(zhuǎn)存快照進(jìn)行分析,重點(diǎn)是確認(rèn)內(nèi)存中的對(duì)象是否是必要的,先分清是因?yàn)閮?nèi)存泄漏(Memory
Leak)還是內(nèi)存溢出(Memory Overflow)。
如果是內(nèi)存泄漏,可進(jìn)一步通過工具查看泄漏對(duì)象到GC Roots的引用鏈。于是就能找到泄漏對(duì)象時(shí)通過怎樣的路徑與GC Roots相關(guān)聯(lián)并導(dǎo)致垃圾收集器無法自動(dòng)回收。
如果不存在泄漏,那就應(yīng)該檢查虛擬機(jī)的參數(shù)(-Xmx與-Xms)的設(shè)置是否適當(dāng)。
2,? 虛擬機(jī)棧和本地方法棧溢出
如果線程請(qǐng)求的棧深度大于虛擬機(jī)所允許的最大深度,將拋出StackOverflowError異常。
如果虛擬機(jī)在擴(kuò)展棧時(shí)無法申請(qǐng)到足夠的內(nèi)存空間,則拋出OutOfMemoryError異常
這里需要注意當(dāng)棧的大小越大可分配的線程數(shù)就越少。
3,? 運(yùn)行時(shí)常量池溢出
異常信息:java.lang.OutOfMemoryError:PermGen space
如果要向運(yùn)行時(shí)常量池中添加內(nèi)容,最簡(jiǎn)單的做法就是使用String.intern()這個(gè)Native方法。該方法的作用是:如果池中已經(jīng)包含一個(gè)等于此String的字符串,則返回代表池中這個(gè)字符串的String對(duì)象;否則,將此String對(duì)象包含的字符串添加到常量池中,并且返回此String對(duì)象的引用。由于常量池分配在方法區(qū)內(nèi),我們可以通過-XX:PermSize和-XX:MaxPermSize限制方法區(qū)的大小,從而間接限制其中常量池的容量。
4,? 方法區(qū)溢出
方法區(qū)用于存放Class的相關(guān)信息,如類名、訪問修飾符、常量池、字段描述、方法描述等。
異常信息:java.lang.OutOfMemoryError:PermGen space
方法區(qū)溢出也是一種常見的內(nèi)存溢出異常,一個(gè)類如果要被垃圾收集器回收,判定條件是很苛刻的。在經(jīng)常動(dòng)態(tài)生成大量Class的應(yīng)用中,要特別注意這點(diǎn)。