JVM之JVM内存溢出

JVM内存溢出

Java内存区域分为程序计数器,方法区,堆区,虚拟机栈和本地方法栈。

其中程序计数器,虚拟机栈和本地方法栈是线程私有的;堆区和方法区是线程共享的。

而在HotSpot虚拟机中是直接将虚拟机栈和本地方法栈合到一起。

  1. 程序计数器。此区域没有定义任何OutOfMemory异常。

  2. 堆区。

    设置堆区大小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)
    
  3. 虚拟机栈

    设置栈大小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
    
    
  4. 方法区

    (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
    
  5. 直接内存溢出

    通过反射获取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)
    
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值