第二章 Java內存區域與內存溢出異常html
一、運行時數據區域java
程序計數器:git
虛擬機棧:github
方法棧:安全
堆:app
方法區:jvm
運行時常量池:ide
直接內存:佈局
二、HotSpot虛擬機對象探祕ui
對象的建立:
內存分配的方式:
保證線程安全的方式:
對象的內存佈局:
對象的訪問定位:
三、OOM異常
package com.ecut.exception; import java.util.ArrayList; import java.util.List; /** * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError */ 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_pid6776.hprof ... Heap dump file created [28247587 bytes in 0.149 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.ecut.exception.HeapOOM.main(HeapOOM.java:17)
package com.ecut.exception; /** * -Xss128k */ public class JavaVMStackSOF { private int stackLength = 1; public void stackLeak(){ stackLength++; stackLeak(); } public static void main(String[] args) { JavaVMStackSOF javaVMStackSOF = new JavaVMStackSOF(); try { javaVMStackSOF.stackLeak(); }catch (Exception e){ System.out.println("stack length :" + javaVMStackSOF.stackLength); throw e; } } }
運行結果以下:
Exception in thread "main" java.lang.StackOverflowError at com.ecut.exception.JavaVMStackSOF.stackLeak(JavaVMStackSOF.java:12)
建立線程致使內存溢出異常:
package com.ecut.exception; /** * -Xss2M */ public class JavaVMStackOOM { private void dontStop(){ while(true){ } } public void stackLeakByThread(){ while (true){ Thread thread = new Thread(new Runnable() { @Override public void run() { dontStop(); } }); thread.start(); } } public static void main(String[] args) { JavaVMStackOOM javaVMStackOOM = new JavaVMStackOOM(); javaVMStackOOM.stackLeakByThread(); } }
package com.ecut.exception; import java.util.ArrayList; import java.util.List; /** * -XX:PermSize=10M -XX:MaxPermSize=10M JDK 1.6 會拋出OOM異常,JDK1.7開始了去永久代 */ public class RuntimeConstantPoolOOM { public static void main(String[] args) { //使用list保持着產量池的引用,避免fullGC回收常量池的行爲 List<String> list = new ArrayList<>(); int i = 0 ; while(true){ list.add(String.valueOf(i++)); } } }
String.intern()方法若是字符串常量池中已經包含了一個等於String對象的字符串,則返回表明池中這個字符串的String對象。不然將此對象包含的字符串添加到常量池中。
package com.ecut.exception; public class RuntimeConstantPool { public static void main(String[] args) { /*jdk1.6 intern方法會把首次遇到的字符串實例複製到永久代中,返回的也是這個永久代中的這個字符串實例的引用。 StringBuilder建立的字符串實例在Java堆上,因此必然不是同一個引用 jdk1.7中intern實現只是在常量池中記錄首次出現的實例引用,所以intern返回的引用和StringBuilder建立的那個字符 串實例時同一個*/ String s1 = new StringBuilder("計算機").append("軟件").toString(); System.out.println(s1.intern() == s1); } }
運行結果:
true
package com.ecut.exception; import sun.misc.Unsafe; import java.lang.reflect.Field; /** * -Xmx20M -XX:MaxDirectMemorySize = 10M */ public class DirectMemoryOOM { private static final int _1MB = 1024*1024; public static void main(String[] args) throws IllegalAccessException { Field unsafeField = Unsafe.class.getDeclaredFields()[0]; unsafeField.setAccessible(true); Unsafe unsafe = (Unsafe) unsafeField.get(null); while (true){ unsafe.allocateMemory(_1MB); } } }
運行結果以下:
Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at com.ecut.exception.DirectMemoryOOM.main(DirectMemoryOOM.java:18)
源碼地址:
https://github.com/SaberZheng/jvm-test
轉載請於明顯處標明出處: