Java 内存模型 - 内存溢出 实战
1、Java 堆内存溢出
Java 堆内存主要用于存放对象实例,只要不断的创建对象,并且摆正GC Roots 到对象之间有可达路径来避免垃圾回收机制清除这些对象,那么在对象创建数量达到堆内存容量限制之后就会产生堆内存OutOfMemoryError 溢出异常。
示例代码:
//VM Args:-Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError
public class test { 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_pid12488.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) at java.util.ArrayList.add(ArrayList.java:458) at com.oops.boot.test.main(test.java:15) Heap dump file created [28410427 bytes in 0.234 secs] Process finished with exit code 1
总结:当对象创建数量达到堆内存容量限制之后就会产生堆内存OutOfMemoryError 溢出异常。例如:无限制创建对象。
2、虚拟机栈 和 本地栈溢出
- 如果线程请求的栈深度大于虚拟机所允许的深度则抛出StackOverflowError异常。
- 如果虚拟机在扩展时无法申请到足够内存空间则抛出OutOfMemoryError 异常。
2.1 StackOverflowError异常
示例代码:
public class JavaVNStackSOF { private int stacklLength = 1; public void stackLeak(){ stacklLength++; stackLeak(); } public static void main(String[] args) throws Throwable{ JavaVNStackSOF oom = new JavaVNStackSOF(); try { oom.stackLeak(); } catch (Exception e) { System.out.println("stack length: " + oom.stacklLength); throw e; } } }
异常代码:
Exception in thread "main" java.lang.StackOverflowError at com.oops.boot.JavaVNStackSOF.stackLeak(JavaVNStackSOF.java:10) at com.oops.boot.JavaVNStackSOF.stackLeak(JavaVNStackSOF.java:11) at com.oops.boot.JavaVNStackSOF.stackLeak(JavaVNStackSOF.java:11) at com.oops.boot.JavaVNStackSOF.stackLeak(JavaVNStackSOF.java:11) 后续省略......
总结:在单个线程下,无论是由于帧太大还是虚拟机容量太小,当内存无法分配的时候,虚拟机都会抛出 StackOverflowError异常。
3、方法区 和运行时常量池溢出
示例代码:
//VM Args : -XX:PermSize=10m -XX:MaxPermSize=10m public class RunTimeConstantPoolOOM { public static void main(String[] args) { List<String> list = new ArrayList<String>(); int i = 0; while (true) { list.add(String.valueOf(i++).intern()); } } }