JVM(第二部分OOM)

140 阅读2分钟

OutOfMemoryError

StackOverflowError

栈满会抛出该错误。无限递归就会导致StackOverflowError,是java.lang.Throwable→java.lang.Error→java.lang.VirtualMachineError下的错误。详见StackOverflowErrorDemo。

public class StackOverflowErrorDemo {
    public static void main(String[] args) {
        stackOverflowError();
    }
    private static void stackOverflowError() {
        stackOverflowError();
    }
}

OOM—Java head space

堆满会抛出该错误。详见JavaHeapSpaceDemo。

//-Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
public class JavaHeapSpaceDemo {
    public static void main(String[] args) {
        String str = "abc";
        while (true) {
            str += str + new Random().nextInt(111111) + new Random().nextInt(222222);
            str.intern();
        }
    }
}

OOM—GC overhead limit exceeded

这个错误是指:GC的时候会有“Stop the World",STW越小越好,正常情况是GC只会占到很少一部分时间。但是如果用超过98%的时间来做GC,而且收效甚微,就会被JVM叫停。下例中,执行了多次Full GC,但是内存回收很少,最后抛出了OOM:GC overhead limit exceeded错误。详见GCOverheadDemo。

//-Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
public class GCOverheadDemo {
    public static void main(String[] args) {
        int i = 0;
        List<String> list = new ArrayList<>();
        try {
            while (true) {
                list.add(String.valueOf(++i).intern());
            }
        } catch (Exception e) {
            System.out.println("*************i" + i);
            e.printStackTrace();
            throw e;
        }
    }
}

OOM—GC Direct buffer memory

在写NIO程序的时候,会用到ByteBuffer来读取和存入数据。与Java堆的数据不一样,ByteBuffer使用native方法,直接在堆外分配内存。当堆外内存(也即本地物理内存)不够时,就会抛出这个异常。详见DirectBufferMemoryDemo。

//-Xms10m -Xmx10m -XX:MaxDirectMemorySize=5m -XX:+PrintGCDetails
public class DirectBufferMemoryDemo {
    public static void main(String[] args) {
        System.out.println("配置的maxDirectMemory: " + (sun.misc.VM.maxDirectMemory() / (double) 1024 / 1024) + "MB");
        try {
            Thread.sleep(300);
        } catch (Exception e) {
            e.printStackTrace();
        }
        ByteBuffer byteBuffer = ByteBuffer.allocateDirect(6 * 1024 * 1024);
    }
}

OOM—unable to create new native thread

在高并发应用场景时,如果创建超过了系统默认的最大线程数,就会抛出该异常。Linux单个进程默认不能超过1024个线程。解决方法要么降低程序线程数要么修改系统最大线程数vim /etc/security/limits.d/90-nproc.conf。详见UnableCreateNewThreadDemo

public class UnableCreateNewThreadDemo {
    public static void main(String[] args) {
        for (int i = 0; ; i++) {
            System.out.println("**********" + i);
            new Thread(() -> {
                try {
                    Thread.sleep(Integer.MAX_VALUE);
                } catch (Exception e) {
                    e.printStackTrace();
                }
            }, i + "").start();
        }
    }
}

OOM—Metaspace

元空间满了就会抛出这个异常。