测试产生Java内存异常

1、 Java堆溢出
Java堆用于储存对象实例,我们只要不断地创建对象,就会在对象数量到达最大堆容量时产生内存溢出异常。
首先我们设置JVM使用的堆大小,设置方式为,点击运行右边的下箭头,并点击“Run Configurations”,在(x)=Argumens一列,在VM argumengs文本框中填写如下内容(设置堆最大空间和最小空间为20M):
-verbose:gc -Xms20M -Xmx20M -Xmn10M -XX:+PrintGCDetails -XX:SurvivorRatio=8
点击“apply”。
我们使用的示例程序如下,不断创建对象,并用List保持对此对象的引用:

import java.util.ArrayList;
import java.util.List;

public class HeapOMM {

    static class OOMobject{
    }

    public static void main(String[] args) {
        List<OOMobject> list = new ArrayList<OOMobject>();
        while(true){
            list.add(new OOMobject());
        }
    }
}

运行后会产生如下异常:
Exception in thread “main” java.lang.OutOfMemoryError: Java heap space
at java.util.Arrays.copyOf(Unknown Source)
at java.util.Arrays.copyOf(Unknown Source)
at java.util.ArrayList.grow(Unknown Source)
at java.util.ArrayList.ensureExplicitCapacity(Unknown Source)
at java.util.ArrayList.ensureCapacityInternal(Unknown Source)
at java.util.ArrayList.add(Unknown Source)
at hanjia.HeapOMM.main(HeapOMM.java:15)

2、 虚拟机栈溢出和本地方法栈溢出
如果线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常,为此我们可以产生一个不会停止的递归调用,则会产生StackOverflowError异常。
我们首先使用-Xss设置栈空间大小,方法如上。使用的程序如下:

public class StackOF {

    private int stackLength = 1;

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

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

异常信息如下:
stack length:11422

Exception in thread “main” java.lang.StackOverflowError
at hanjia.StackOF.stackLeak(StackOF.java:8)
at hanjia.StackOF.stackLeak(StackOF.java:9)

3、 运行时常量池溢出
如果要向运行时常量池中添加内容,最简单的做法就是使用String.intern()这个Native方法。该方法的作用是:如果池中已经包含一个等于此String对象的字符串,则返回代表池中这个字符串的String对象;否则,将此String对象包含的字符串添加到常量池中,并且返回次String对象的引用。由于常量池分配在方法区中,我们可以通过 -XX:PermSize和 –XX:MaxPermSize限制方法区的大小,从而间接控制其中常量池的容量。设置的参数为(必须为英文字符):
-XX:PermSize=2M -XX:MaxPermSize=2M

代码清单如下:

import java.util.ArrayList;
import java.util.List;

public class RuntimeConstantPoolOOM {

    public static void main(String[] args) {

        //使用List保持对常量池的引用,避免Full GC回收常量池行为
        List<String> list = new ArrayList<String>();
        int i=0;
        while(true){
            list.add(String.valueOf(i++).intern());
            list.add(String.valueOf(i++).intern());
            list.add(String.valueOf(i++).intern());
            list.add(String.valueOf(i++).intern());
        }
    }
}

出现的错误如下:
Error occurred during initialization of VM
java.lang.OutOfMemoryError: PermGen space
at java.util.Locale.createConstant(Unknown Source)
at java.util.Locale.(Unknown Source)
at java.io.Win32FileSystem.hashCode(Unknown Source)
at java.io.File.hashCode(Unknown Source)
at java.util.HashMap.hash(Unknown Source)
at java.util.HashMap.put(Unknown Source)
at sun.misc.MetaIndex.registerDirectory(Unknown Source)
at sun.misc.Launcher ExtClassLoader 1.run(Unknown Source)
at sun.misc.Launcher ExtClassLoader 1.run(Unknown Source)
at java.security.AccessController.doPrivileged(Native Method)
at sun.misc.Launcher$ExtClassLoader.getExtClassLoader(Unknown Source)
at sun.misc.Launcher.(Unknown Source)
at sun.misc.Launcher.(Unknown Source)
at java.lang.ClassLoader.initSystemClassLoader(Unknown Source)
at java.lang.ClassLoader.getSystemClassLoader(Unknown Source)

节选自:《深入理解Java虚拟机》周志明

你可能感兴趣的:(测试产生Java内存异常)