標籤:java-堆溢出
是一張Java運行時的記憶體分布圖,可知虛擬機器記憶體都有發生OutOfMemoryError(下文稱 OOM)異常的可能,作為一個合格的Java開發人員,我們應該做到的是:
(1)第一,通過代碼驗證 JAVA 虛擬機器規範中描述的各個運行時地區儲存的內容;
(2)第二,遇到記憶體溢出的時候,應該可以找打具體的位置,並進行合理的解決;
下邊就聊一下 OOM:
一、Java 堆溢出
我們知道Java 堆用於儲存對象執行個體,我們只要不斷地建立對象,並且保證 GC Roots 到對象之間有可達路徑來避免記憶體回收機制清除這些對象,就會在對象數量到達最大堆的容量限制後產生記憶體溢出異常(OOM)。
案例如下:
/** * VM Args: -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError * 需要在jre1.5下編譯 * @author xuliugen */public class HeapOOM { static class OOMObject{} public static void main(String[] args){ List<OOMObject> list = new ArrayList<OOMObject>(); while(true){ list.add(new OOMObject()); } }}
為了能夠看到記憶體溢出時候的狀態資訊,在項目右鍵–run as –run configuration –Arguments
然後可以看到爆出一下錯誤:
java.lang.OutOfMemoryError: Java heap spaceDumping heap to java_pid6424.hprof ...Heap dump file created [28129384 bytes in 0.118 secs]Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Unknown Source) at java.util.Arrays.copyOf(Unknown Source) at java.util.ArrayList.grow(Unknown Source) at java.util.ArrayList.ensureExplicitCapacity(Unknown Source) at java.util.ArrayList.ensureCapacityInternal(Unknown Source) at java.util.ArrayList.add(Unknown Source) at com.lc.oom.HeapOOM.main(HeapOOM.java:21)
Java 堆記憶體的 OOM 異常是實際應用中最常見的記憶體溢出異常情況。出現 Java 堆記憶體溢出時,異常堆棧資訊“java.lang.OutOfMemoryError”會跟著進一步提示“Java heap space”。要解決這個地區的異常,一般的方法是首先通過記憶體映像分析工具(如 Eclipse Memory Analyzer)對 dump 出來的堆轉儲快照進行分析,重點是確認記憶體中的對象是否是必要的,也就是要先分清楚到底是出現了記憶體流失( Memory Leak)還是記憶體溢出( Memory Overflow)。可以使用 EclipseMemory Analyzer 開啟的堆轉儲快照檔案。( Eclipse Memory Analyzer是一個eclipse外掛程式,網上百度一下,很多)
如果是記憶體流失,可進一步通過工具查看泄漏對象到 GC Roots 的引用鏈。於是就能找到泄漏對象是通過怎樣的路徑與 GC Roots 相關聯並導致垃圾收集器無法自動回收它們的。握了泄漏對象的類型資訊,以及 GC Roots 引用鏈的資訊,就可以比較準確地定位出泄漏代碼的位置。
如果不存在泄漏,換句話說就是記憶體中的對象確實都還必須存活著,那就應當檢查虛擬機器的堆參數( -Xmx 與-Xms),與機器實體記憶體對比看是否還可以調大,從代碼上檢查是否存在某些對象生命週期過長、持有狀態時間過長的情況,嘗試減少程式運行期的記憶體消耗。
以上是處理 Java 堆記憶體問題的簡略思路。
下一篇,講學習一下 : 虛擬機器棧和本地方法棧溢出
Java虛擬機器OutOfMemoryError 異常詳解及解決方案(3)