在各個運行時區(qū)域中叠殷,除了程序計數(shù)器,其他存儲區(qū)都有可能發(fā)生OutOfMemoryError異常
Java堆溢出
- Java堆內(nèi)存的OOM異常是實際應(yīng)用中常見的內(nèi)存溢出異常情況碱璃。當出現(xiàn)Java堆內(nèi)存溢出時菩鲜,異常堆棧信息“java.lang.OutOfMemoryError”會跟著進一步提示“Java heapspace”
- 要解決這個區(qū)域的異常淋样,一般的手段是先通過內(nèi)存映像分析工具(如Eclipse Memory Analyzer)對Dump出來的堆轉(zhuǎn)儲快照進行分析作岖,重點是確認內(nèi)存中的對象是否是必要的唆垃,也就是要先分清楚到底是出現(xiàn)了內(nèi)存泄漏(Memory Leak)還是內(nèi)存溢出(Memory Overflow)
- 如果是內(nèi)存泄露,可進一步通過工具查看泄露對象到GCRoots的引用鏈痘儡。于是就能找到泄露對象是通過怎樣的路徑與GC Roots相關(guān)聯(lián)并導(dǎo)致垃圾收集器無法自動回收它們的
- 如果不存在泄露辕万,換句話說,就是內(nèi)存中的對象確實都還必須存活著沉删,那就應(yīng)當檢查虛擬機的堆參數(shù)(-Xmx與-Xms)渐尿,與機器物理內(nèi)存對比看是否還可以調(diào)大,從代碼上檢查是否存在某些對象生命周期過長矾瑰、持有狀態(tài)時間過長的情況砖茸,嘗試減少程序運行期的內(nèi)存消耗
虛擬機棧和本地方法棧溢出
- 如果線程請求的棧深度大于虛擬機所允許的最大深度,將拋出StackOverflowError異常
- 如果虛擬機在擴展棧時無法申請到足夠的內(nèi)存空間殴穴,則拋出OutOfMemoryError異常
方法區(qū)和運行時常量池溢出
- String.intern()是一個Native方法凉夯,它的作用是:如果字符串常量池中已經(jīng)包含一個等于此String對象的字符串,則返回代表池中這個字符串的String對象采幌;否則劲够,將此String對象包含的字符串添加到常量池中,并且返回此String對象的引用
- 在JDK1.6及之前的版本中休傍,由于常量池分配在永久代內(nèi)征绎,我們可以通過-XX:PermSize和-XX:MaxPermSize限制方法區(qū)大小,從而間接限制其中常量池的容量
- 在JDK 1.6中磨取,intern()方法會把首次遇到的字符串實例復(fù)制到永久代中人柿,返回的也是永久代中這個字符串實例的引用,而由String-Builder創(chuàng)建的字符串實例在Java堆上寝衫,所以必然不是同一個引用顷扩,將返回false。而JDK 1.7(以及部分其他虛擬機慰毅,例如JRockit)的intern()實現(xiàn)不會再復(fù)制實例隘截,只是在常量池中記錄首次出現(xiàn)的實例引用,因此intern()返回的引用和由String-Builder創(chuàng)建的那個字符串實例是同一個
- 運行時常量池溢出汹胃,在Out-OfMemoryError后面跟隨的提示信息是“PermGen space”婶芭,說明運行時常量池屬于方法區(qū)(HotSpot虛擬機中的永久代)的一部分
- 方法區(qū)溢出也是一種常見的內(nèi)存溢出異常,一個類要被垃圾收集器回收掉着饥,判定條件是比較苛刻的
本機直接內(nèi)存溢出
- 由DirectMemory導(dǎo)致的內(nèi)存溢出犀农,一個明顯的特征是在Heap Dump文件中不會看見明顯的異常,如果讀者發(fā)現(xiàn)OOM之后Dump文件很小宰掉,而程序中又直接或間接使用了NIO呵哨,那就可以考慮檢查一下是不是這方面的原因