Java堆溢出
虛擬機參數:
-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
將堆的最小值和最大值都限制成為20M,-XX:+HeapDumpOnOutOfMemoryError出現內存異常時令java虛擬機Dump堆內存轉儲快照
代碼
1 import java.util.*; 2 3 /** 4 * Created by zcy on 2017/6/11. 5 */ 6 public class TestHeapMemory { 7 8 static class OOMObject{ 9 10 } 11 12 public static void main(String[] args){ 13 List<OOMObject> list = new ArrayList<OOMObject>(); 14 while (true){ 15 list.add(new OOMObject()); 16 } 17 } 18 }
運行出現異常:
java.lang.OutOfMemoryError: Java heap space Dumping heap to java_pid9392.hprof ... 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) Heap dump file created [28361944 bytes in 0.134 secs] at java.util.ArrayList.add(ArrayList.java:458) at TestHeapMemory.main(TestHeapMemory.java:15)
為了查看實時堆的使用情況,我們可以安裝VisualVM Launcher。
安裝請參考http://www.oschina.net/translate/setting-up-visualvm-in-under-5-minutes
使用VisualVM Launcher調試程序(需要在程序中sleep延時),發現堆內存一路上漲,最后崩掉了。
查看dump file,絕大多數內存都被數組占用了
要解決Heap的OutOfMemory,一般的手段是使用內存映像分析工具,分析堆轉儲文件,重點是確認內存中的對象是否是必要的,也就是要先分清楚到底是出現了內存泄露還是內存溢出。
如果是內存泄露,可以進一步使用工具查看到GC Roots的引用鏈。於是就能找到泄露對象是通過怎樣的路徑與GC Roots相關聯,導致GC無法自動回收。
如果每個對象都有必要存活着,那么應該檢查堆參數(-Xms和-Xmx)是否還可以調大
虛擬機棧和本地方法棧溢出
兩種異常:
- StackOverFlow異常:線程請求的棧深度大於虛擬機允許的最大深度。
- OutOfMemory異常:虛擬機擴展棧時無法申請到足夠的內存空間。
虛擬機參數:
-Xss128k
代碼:
1 /** 2 * Created by zcy on 2017/6/11. 3 */ 4 public class TestStackOF { 5 6 private static int stackLength = 0; 7 8 public static void stackLeak() throws InterruptedException { 9 stackLength++; 10 stackLeak(); 11 } 12 13 public static void main(String args[]) throws Throwable { 14 try{ 15 TestStackOF.stackLeak(); 16 } 17 catch (Throwable e){ 18 System.out.println("stack length is: " + stackLength); 19 throw e; 20 } 21 } 22 }
運行結果:
stack length is: 1102 Exception in thread "main" java.lang.StackOverflowError at TestStackOF.stackLeak(TestStackOF.java:9) at TestStackOF.stackLeak(TestStackOF.java:10) at TestStackOF.stackLeak(TestStackOF.java:10) at TestStackOF.stackLeak(TestStackOF.java:10) ...
最后總結一下:
- 對於StackOverFlow異常:棧深度(1000-2000)絕大多數情況下都夠用了。有錯誤堆棧可以閱讀。
- 如果由於建立線程過多導致的內存溢出,可以減少堆容量和每個進程的棧容量換取更多的線程。
方法區和運行時常量池溢出