1.首先這里先說一下內存溢出和內存泄露的區別:
內存溢出 out of memory,是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory;比如申請了一個integer,但給它存了long才能存下的數,那就是內存溢出。
內存泄露 memory leak,是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存,遲早會被占光。
memory leak會最終會導致out of memory!
2.我們這里做一個內存溢出的例子
/** * VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError * @author Administrator * */ public class TestDump { static class OOB { } public static void main(String[] args) { List<OOB> list = new ArrayList<OOB>(); while (true) { list.add(new OOB()); } } }
其中-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError是需要加的JVM啟動參數
-Xms20m將堆的最小值設置為20MB,-Xmx20m將堆的最大值設置為20MB,當設置一樣時即可避免堆自動擴展。
-XX:+HeapDumpOnOutOfMemoryError可以讓虛擬機在內存溢出時Dump當前的內存堆轉儲快照以便事后進行分析。
運行結果:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid6256.hprof ... Heap dump file created [27904625 bytes in 0.098 secs] Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at java.util.Arrays.copyOf(Arrays.java:2245) at java.util.Arrays.copyOf(Arrays.java:2219) at java.util.ArrayList.grow(ArrayList.java:242) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:216) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:208) at java.util.ArrayList.add(ArrayList.java:440) at com.webservie.TestDump.main(TestDump.java:18)
異常信息java.lang.OutOfMemoryError: Java heap space。解決該區域問題,一般先通過內存印象分析工具(如Eclipse Memory Analyzer)對Dump出來的堆轉儲快照進行分析,重點是確認內存中的對象是否是必要的,
要就是先要分清楚到底是出現了內存泄露還是內存溢出。
java_pid6256.hprof就是生成的快照,可以在類所在的工程根目錄下找到。
打開該快照文件,如圖所示:
如果是內存泄露,可進一步通過工具查看泄露對象到GC Roots的引用鏈。於是就能找到泄露對象是通過怎樣的路徑與GC Roots相關聯並導致垃圾收集器無法自動回收它們的。
掌握了泄露對象的類型信息及GC Roots引用鏈的信息,就可以比較准確的定位出泄露代碼的位置。
如果不存在泄露,就是內存中的對象確實都還必須存活着,就應該檢測虛擬機的堆參數(-Xmx和-Xms),與機器物理內存對比,看看是否可以調大,從代碼上檢查是否存在某些
對象生命周期過長、持有狀態時間過長的情況,嘗試減少程序運行期的內存消耗。