JVM内存溢出
Java内存区域分为程序计数器,方法区,堆区,虚拟机栈和本地方法栈。
其中程序计数器,虚拟机栈和本地方法栈是线程私有的;堆区和方法区是线程共享的。
而在HotSpot虚拟机中是直接将虚拟机栈和本地方法栈合到一起。
-
程序计数器。此区域没有定义任何OutOfMemory异常。
-
堆区。
设置堆区大小20M,不可扩展;通过list保持对象到GC Roots可达。
-Xms20M -Xmx20M -XX:+HeapDumpOnOutOfMemoryError
public class HeapTestMain { 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_pid23352.hprof ... Heap dump file created [28245988 bytes in 0.065 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:265) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231) at java.util.ArrayList.add(ArrayList.java:462) at oomtest.HeapTestMain.main(HeapTestMain.java:15)
-
虚拟机栈
设置栈大小128K
-Xss128K
单一线程环境下,循环递归,增加栈长度。
public class StackTestMain { static class StackOOMObject{ private int len = 0; public void stackLeak() { len++; stackLeak(); } } public static void main(String[] args) { StackOOMObject obj = new StackOOMObject(); try { obj.stackLeak(); } catch (Error e) { System.out.println(obj.len); throw e; } } }
996 Exception in thread "main" java.lang.StackOverflowError at oomtest.StackTestMain$StackOOMObject.stackLeak(StackTestMain.java:11) at oomtest.StackTestMain$StackOOMObject.stackLeak(StackTestMain.java:12) at oomtest.StackTestMain$StackOOMObject.stackLeak(StackTestMain.java:12) at ... oomtest.StackTestMain$StackOOMObject.stackLeak(StackTestMain.java:12) at oomtest.StackTestMain.main(StackTestMain.java:19) Process finished with exit code 1
-
方法区
(1) 运行时常量池
版本差异:
JDK1.6之前,方法区包括运行时常量池在永久代中;
JDK1.7,方法区和运行时常量池在永久代,字符串常量池在堆中;
JDK1.8,永久代被废弃,方法区在元空间,运行时常量池和字符串常量池在堆中。
程序:
public class MethodAreaTestMain { public static void main(String[] args) { List<String> list = new ArrayList(); String str = ""; while(true) { for(int i=0;i<10;i++) { list.add((str+i).intern()); } list.add((str=str+"0").intern()); } } }
设置永久代10M,不可扩展
-XX:PermSize=10M -XX:MaxPermSize=10M
jdk1.6运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java from InputFileObject:15)
jdk1.7运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java:15)
jdk1.8运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: Java heap space at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java:15) Java HotSpot(TM) 64-Bit Server VM warning: ignoring option PermSize=10M; support was removed in 8.0 Java HotSpot(TM) 64-Bit Server VM warning: ignoring option MaxPermSize=10M; support was removed in 8.0
设置堆区10M,不可扩展
-Xms10M -Xmx10M
jdk1.8运行结果:
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:265) at java.util.ArrayList.ensureExplicitCapacity(ArrayList.java:239) at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:231) at java.util.ArrayList.add(ArrayList.java:462) at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java:15)
jdk1.7执行结果:
Exception in thread "main" java.lang.OutOfMemoryError: GC overhead limit exceeded at java.util.Arrays.copyOf(Arrays.java:2367) at java.lang.AbstractStringBuilder.expandCapacity(AbstractStringBuilder.java:130) at java.lang.AbstractStringBuilder.ensureCapacityInternal(AbstractStringBuilder.java:114) at java.lang.AbstractStringBuilder.append(AbstractStringBuilder.java:415) at java.lang.StringBuilder.append(StringBuilder.java:132) at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java:15)
jdk1.6运行结果:
Exception in thread "main" java.lang.OutOfMemoryError: PermGen space at java.lang.String.intern(Native Method) at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java from InputFileObject:15)
(2) 方法区
通过cglib,动态生成大量代理类。
public class MethodAreaTestMain { static class MethodAreaOOMObject {} public static void main(String[] args) { while(true) { Enhancer enhancer = new Enhancer(); enhancer.setSuperclass(MethodAreaOOMObject.class); enhancer.setUseCache(false); enhancer.setCallback(new MethodInterceptor() { public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable { return methodProxy.invokeSuper(o, objects); } }); enhancer.create(); } } }
设置永久代10M
-XX:PermSize=10M -XX:MaxPermSize=10M
jdk1.6结果:
Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:256) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:378) at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:286) at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java from InputFileObject:24) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25) at java.lang.reflect.Method.invoke(Method.java:597) at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:395) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237) ... 3 more Caused by: java.lang.OutOfMemoryError: PermGen space at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClassCond(ClassLoader.java:631) at java.lang.ClassLoader.defineClass(ClassLoader.java:615) ... 8 more
jdk1.7结果:
Exception in thread "main" Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"
设置元空间10M jdk1.8结果:
Exception in thread "main" net.sf.cglib.core.CodeGenerationException: java.lang.reflect.InvocationTargetException-->null at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:256) at net.sf.cglib.proxy.Enhancer.createHelper(Enhancer.java:378) at net.sf.cglib.proxy.Enhancer.create(Enhancer.java:286) at oomtest.MethodAreaTestMain.main(MethodAreaTestMain.java:27) Caused by: java.lang.reflect.InvocationTargetException at sun.reflect.GeneratedMethodAccessor1.invoke(Unknown Source) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at net.sf.cglib.core.ReflectUtils.defineClass(ReflectUtils.java:395) at net.sf.cglib.core.AbstractClassGenerator.create(AbstractClassGenerator.java:237) ... 3 more Caused by: java.lang.OutOfMemoryError: Metaspace at java.lang.ClassLoader.defineClass1(Native Method) at java.lang.ClassLoader.defineClass(ClassLoader.java:763) ... 8 more
-
直接内存溢出
通过反射获取sun.misc.Unsafe实例分配内存。
public class DirectMemoryTestMain { static int _1MB = 1024 * 1024; public static void main(String[] args) throws IllegalAccessException { Field field = Unsafe.class.getDeclaredFields()[0]; field.setAccessible(true); Unsafe unsafe = (Unsafe)field.get(null); while(true) { unsafe.allocateMemory(_1MB); } } }
结果:
Exception in thread "main" java.lang.OutOfMemoryError at sun.misc.Unsafe.allocateMemory(Native Method) at oomtest.DirectMemoryTestMain.main(DirectMemoryTestMain.java:17)