Java虛擬機運行數據區
Java堆用於存儲對象實例,只要不斷地創建對象,並且保證GC Roots到對象之間有可達到路徑來避免垃圾回收機制清除這些對象,那么在對象數量達到最大堆的容量限制后就會產生內存溢出異常。
Java堆內存溢出異常測試代碼:
/** * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError * * -Xms20m:堆的最小值為20MB * -Xmx20m:堆的最大值為20MB * -XX:+HeapDumpOnOutOfMemoryError 讓虛擬機在出現內存溢出異常時Dump出當前的內存堆轉儲快照 * */ public class HeapOOM { static class OOMObject { } public static void main(String[] args) { List<OOMObject> list = new ArrayList<>(); while(true) { list.add(new OOMObject()); } } }
運行結果:
java.lang.OutOfMemoryError: Java heap space
Dumping heap to java_pid8660.hprof ...
Heap dump file created [28027169 bytes in 0.111 secs]
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Arrays.java:3210)
at java.util.Arrays.copyOf(Arrays.java:3181)
at java.util.ArrayList.grow(ArrayList.java:261)
at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:235)
at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:227)
at java.util.ArrayList.add(ArrayList.java:458)
at com.yucong.jvm.HeapOOM.main(HeapOOM.java:25)
要解決java heap space這個區域的異常,一般的手段是先通過內存映像分析工具(如:Eclipse Memory Analyzer)對Dump出來的堆轉儲快照進行分析,重點是確認內存中對象是否必要的,也就是要先分清楚到底是出現了內存泄漏(Memory Leak)還是內存溢出(Memory Overflow)。
安裝Eclipse Memory Analyzer工具:
點擊菜單:Help的子菜單Eclipse Marketplace,輸入Eclipse Memory Analyzer,搜索結果如下:
運行參數配置:
運行完后,刷新一下項目,會多出一個hrpof文件:
打開此文件,默認第一項Leak Suspects Report,直接Finish:
點擊Details:
以上是處理Java堆內存問題的簡單思路:【來自《深入理解Java虛擬機》】
如果是內存泄漏,可進一步通過工具查看泄漏對象到GC Roots的引用鏈。於是就能找到泄漏對象是通過怎樣的路徑與GC Roots相關聯並導致垃圾收集器無法自動回收它們的。掌握了泄漏對象的類型信息及GC Roots引用鏈的信息,就可以比較准確地定位出泄漏代碼的位置。
如果不存在泄漏,換句話說,就是內存中的對象確實還必須存活着,那就應當檢查虛擬機的堆參數(-Xmx 與 -Xms),與機器物理內存對比看是否可以調大,從代碼上檢查是否存在某些對象生命周期過長、持有狀態時間過長的情況,嘗試減少程序運行期的內存消耗。