Java虚拟机内存溢出异常

    前几天读《深入理解Java虚拟机》测试了一下书中所写的java虚拟机异常的代码,特在此整理一下。

Java堆溢出

    众所周知,JVM(java虚拟机)中堆是用于存放对象实例的,想要令其发生溢出,只需要不断创造对象便可。
    代码如下:

public class HeapOOM {

    static class OOMObject {}

    public static void main(String[] args) {
        List list = new ArrayList();
        int i = 0;
        while (true) {
            list.add(new OOMObject());
        }
    }

}

运行结果:

java.lang.OutOfMemoryError: Java heap space

栈溢出

    java中栈分为两类:Java虚拟机栈和本地方法栈,java虚拟机栈为java虚拟机的方法提供服务,而本地方法栈则是为虚拟机使用的Native方法提供服务。二者的溢出方式均相同,都可分为两种:

  • 线程请求深度大于虚拟机允许的最大深度,抛出StackOverflowError异常
  • 虚拟机扩展栈时无法申请到足够的内存空间,就会抛出OutOfMemeoryError异常

    栈深度溢出的代码如下:

public class JavaVMStackSOF {

    private int stackLength = 1;

    public void stackLeak(){
        stackLength++;
        stackLeak();
    }

    public static void main(String[] args) throws Throwable {
        JavaVMStackSOF oom = new JavaVMStackSOF();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:"+oom.stackLength);
            throw e;
        }
    }

}

运行结果:

stack length:9506
 *      Exception in thread "main" java.lang.StackOverflowError

栈容量溢出:
    此处书中代码有问题,本人未能成功测试(毕竟是国人写的书,质量不过关)。真正的测试代码日后另行附上。。。

运行时常量池溢出

    java虚拟机中运行时常量池是java虚拟机中方法区的一部分,用于存放编译期生成的各类字面量和符号引用。
    想要使运行时常量池溢出,需要用到String.intern()这个Native方法。该方法的作用是:如果池中包含此String对象的字符串,则返回池中这个字符串的String对象;否则将此对象所包含的字符串添加到常量池中,并返回此String对象的引用。
    代码如下

public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {
        List list = new ArrayList();
        int i = 0;
        while (true) {
            list.add(String.valueOf(i++).intern());
        }
    }

}

运行结果“

java.lang.OutOfMemoryError: PermGen space

方法区溢出

    方法区用于存放Class的相关信息,如类名、访问修饰符、常量池、字段描述、方法描述等。这个测试基本方法是产生大量的类去填充方法区。
    但由于这个测试书中借用了CGLib项目,本人手上无此项目,故未做测试,先将代码附上吧:

public class JavaMethodAreaOOM{
    public static void main(String[] args){
        while(true){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(OOMObject.class);
            enhancer.setUseCache(false);
            enhancer.setCallback(new MethodInterceptor(){
                public Object intercept(Object obj,Method method,Object args,MethodProxy proxy) throws Throeable{
                    return proxy.invokeSuper(obj,args);
                }
            });
            enchaner.create();
        }
    }
    static class OOMObject {}
}

本机直接内存溢出

    本机直接内存抛出异常的代码如下:

public class DirectMemoryOOM {

    private static final int _1MB = 1024*1024;

    public static void main(String[] args) throws Exception {
        Field unsafeField = Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true) {
            unsafe.allocateMemory(_1MB);
        }
    }

}

运行结果为:

java.lang.OutOfMemoryError

你可能感兴趣的:(Java核心)