Java堆用於存儲對象實例,只要不斷地建立對象,而且保證GC Roots到對象之間有可達
路徑來避免垃圾回收機制清除這些對象,那麼在對象數量到達最大堆的容量限制後就會產生
內存溢出異常。java
示例代碼 :markdown
/** *VM Args:-Xms20m-Xmx20m-XX:+HeapDumpOnOutOfMemoryError *@author zzm */ public class HeapOOM{ static class OOMObject{ } public static void main(String[]args){ List<OOMObject>list=new ArrayList<OOMObject>(); while(true){ list.add(new OOMObject()); } } }
運行結果 :多線程
java.lang.OutOfMemoryError:Java heap space Dumping heap to java_pid3404.hprof…… Heap dump file created[22045981 bytes in 0.663 secs]
Java堆內存的OOM異常是實際應用中常見的內存溢出異常狀況。當出現Java堆內存溢出
時,異常堆棧信息「java.lang.OutOfMemoryError」會跟着進一步提示「Java heap space」。
要解決這個區域的異常,通常的手段是先經過內存映像分析工具(如Eclipse Memory
Analyzer)對Dump出來的堆轉儲快照進行分析,重點是確認內存中的對象是不是必要的,也
就是要先分清楚究竟是出現了內存泄漏(Memory Leak)仍是內存溢出(Memory
Overflow)。工具
若是是內存泄露,可進一步經過工具查看泄露對象到GC Roots的引用鏈。因而就能找到
泄露對象是經過怎樣的路徑與GC Roots相關聯並致使垃圾收集器沒法自動回收它們的。掌握
了泄露對象的類型信息及GC Roots引用鏈的信息,就能夠比較準確地定位出泄露代碼的位
置。
若是不存在泄露,換句話說,就是內存中的對象確實都還必須存活着,那就應當檢查虛
擬機的堆參數(-Xmx與-Xms),與機器物理內存對比看是否還能夠調大,從代碼上檢查是
否存在某些對象生命週期過長、持有狀態時間過長的狀況,嘗試減小程序運行期的內存消
耗。spa
關於虛擬機棧和本地方法棧,在Java虛擬機規範中描述了兩種異常:
若是線程請求的棧深度大於虛擬機所容許的最大深度,將拋出StackOverflowError異常。
若是虛擬機在擴展棧時沒法申請到足夠的內存空間,則拋出OutOfMemoryError異常。線程
這裏把異常分紅兩種狀況,看似更加嚴謹,但卻存在着一些互相重疊的地方:當棧空間
沒法繼續分配時,究竟是內存過小,仍是已使用的棧空間太大,其本質上只是對同一件事情
的兩種描述而已。
錯誤結果示例:code
stack length:2402 Exception in thread"main"java.lang.StackOverflowError
出現StackOverflowError異常時有錯誤
堆棧能夠閱讀,相對來講,比較容易找到問題的所在。
可是,若是是創建過多線程致使的內存溢出,在不能減小線程數或者更換64位虛
擬機的狀況下,就只能經過減小最大堆和減小棧容量來換取更多的線程。若是沒有這方面的
處理經驗,這種經過「減小內存」的手段來解決內存溢出的方式會比較難以想到。server
運行時常量池是方法區的一部分
方法區用於存放Class的相關信息,如類名、訪問修飾符、常量池、字段描述、方法描述
等。
溢出狀況說明:
1.運行時添加到常量池中的字面量和符號引用過多,致使溢出
2.運行時產生大量的類填滿方法區,致使溢出。
示例結果:對象
Exception in thread"main"java.lang.OutOfMemoryError:PermGen space at java.lang.String.intern(Native Method) at org.fenixsoft.oom.RuntimeConstantPoolOOM.main(RuntimeConstantPoolOOM.java:18)
從運行結果中能夠看到,運行時常量池溢出,在OutOfMemoryError後面跟隨的提示信息
是「PermGen space」,說明運行時常量池屬於方法區(HotSpot虛擬機中的永久代)的一部
分。生命週期
DirectMemory容量可經過-XX:MaxDirectMemorySize指定,若是不指定,則默認與Java
堆最大值(-Xmx指定)同樣.
由DirectMemory致使的內存溢出,一個明顯的特徵是在Heap Dump文件中不會看見明顯
的異常,若是發現OOM以後Dump文件很小,而程序中又直接或間接使用了NIO,那就
能夠考慮檢查一下是否是這方面的緣由。
運行結果:
Exception in thread"main"java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at org.fenixsoft.oom.DMOOM.main(DMOOM.java:20)