二、JVM(HotSpot)内存泄漏和内存溢出

注:本博文主要是基于JDK1.7会适当加入1.8内容。

1、Java堆溢出

//-Xms20m -Xms20m -XX:+HeapDumpOnOutOfMemoryError
public class HeapOOM {
    static class OOMObject {}

    public static void main(String[] args) {
        List<OOMObject> list = new ArrayList<>();

        while(true) {
            list.add(new OOMObject());
        }
    }

}

运行上述代码,出现内存溢出错误即OutOfMemoryError,错误信息为参数-XX:HeapDumpOnOutOfMemoryError导出一份java_podxxxx.hprof的文件。分析dump文件,打开visualVM导入查看。(JDK中包含jvisualVM工具可进行查看)

题外话:出现OutOfMemoryError除了有内存溢出的可能性之外还存在内存泄漏的可能性。如果是内存溢出,则需要查看泄漏对象的GC Root的引用链。如果不是内存泄漏则可能是内存溢出,首先尝试调大-Xms和-Xmx,如果还是报错需要定位代码的问题(dump文件分析)

2、虚拟机栈和本地方法栈溢出

由于HotSpot虚拟机中不区分虚拟机栈和本地方法栈,一致通过-Xss调整栈内存大小。
如果线程请求的栈深度大于虚拟机所允许的最大深度则抛出StackOverflowError;如果虚拟机扩展栈内存无法申请到足够的内存空间时则抛出OutOfMemoryError。

//-Xss128k
public  class JavaVMStackSOF {

    private int stackLength = 1;

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

    public static void main(String[] args) {
        JavaVMStackSOF sof = new JavaVMStackSOF();

        try{
            sof.stackLeak();
        } catch(Throwable e) {
            throw e;
        }
    }

}

运行上述代码,出现内存溢出错误即OutOfMemoryError。在单线程下,由于栈帧太大还是虚拟机栈容量太小,当内存无法分配的时候虚拟机抛出的都是OutOfMemoryError。然而,在多线程情况下,是可以出现StackOverflowError,虚拟机为每个进程提供内存都是有限制的,栈内存大小约等于物理内存减去最大堆内存和方法区容量(JDK1.8已经替换为Metaspace),每个线程分配到的栈容量越大则可建立的线程数越少,简历线程就可以将剩余的内存耗尽。

//-Xss2m
public class JavaVMStackOOM {

    private void doNotStop() {
        while(true) {}

        private void stackLeakByThread() {
            while(true) {
                Thread thread = new Thread(()-> doNotStop());
                thread.start();
            }
        }

        public static void main(String[] args) {
            JavaVMStackOOM oom = new JavaVMStackOOM();
            oom.stackLeakByThread();
        }
    }
}

注意:这段代码如果执行在Windows操作系统中,会导致系统假死现象,原因是Java的线程会映射到操作系统的内核线程上(需要重启机器)。

3、方法区和运行时常量池溢出(运行时常量池JDK1.7移除方法区,JDK1.8已经移除方法区设置Metaspace)

请参考上一章String.intern代码解释。

4、直接内存溢出

直接内存容量可以通过参数-XX:MaxDirectMemorySize指定,若不指定则默认与Java堆最大值(-Xmx)一样。直接内存溢出明显特征是Heap Dump文件中不会看见明显的异常排除堆内存溢出。

猜你喜欢

转载自blog.csdn.net/zhangwei408089826/article/details/81607466