读 - 深入理解java虚拟机 - 笔记(八-1) - Java内存溢出异常(2章)

Java堆溢出

堆内存储对象实例,因此只要不断创建对象,并且保证GC Roots到对象之间有可达路径以免垃圾回收机制清除对象。

/**
 * @author: wayne
 * @desc:
 * @date: 2018/5/10 14:47
 * @version: 1.0
 *   -Xms20M
 *   -Xmx20M
 *   -Xmn10M
 *   -XX:+HeapDumpOnOutOfMemoryError
 *   -XX:HeapDumpPath=/dump/
 */
public class TestOom {
    public static void main(String[] args) throws Exception {
        List<TestOom> list = new ArrayList<TestOom>();
        while (true){
            list.add(new TestOom());
        }
    }
}

输出结果:

java.lang.OutOfMemoryError: Java heap space
Dumping heap to /dump/\java_pid7088.hprof ...
Exception in thread "main" Heap dump file created [28239072 bytes in 0.117 secs]
java.lang.OutOfMemoryError: Java heap space
	at java.util.Arrays.copyOf(Arrays.java:2245)
	at java.util.Arrays.copyOf(Arrays.java:2219)
	at java.util.ArrayList.grow(ArrayList.java:213)
	at java.util.ArrayList.ensureCapacityInternal(ArrayList.java:187)
	at java.util.ArrayList.add(ArrayList.java:411)
	at TestOom.main(TestOom.java:17)

Process finished with exit code 1

至于生成的这个文件怎么去解析,后续会有文章跟进,本篇不去关注。堆的异常会生成下面明显的报错:

java.lang.OutOfMemoryError: Java heap space

分析过程简单概括:

首先需要分析出是内存泄漏还是内存溢出

1. 内存泄漏(Memory Leak):程序在申请内存后无法释放已使用的空间,累积会导致最终的内存溢出。

查找过程需要利用工具查看泄漏对象到GC Roots的引用链,定位出为什么具体路径,根据路径查找准确的代码位置。

2. 内存溢出(Memory Overflow):程序在申请内存时没有足够的空间供其使用。

首先看能不能提高虚拟机参数。其次检查代码中哪些对象生命周期过长,尝试减少这些消耗。

Java栈溢出

/**
 * @author: wayne
 * @desc:
 * @date: 2018/5/10 14:47
 * @version: 1.0
 *   -Xss128K
 */
public class TestOom {

    private int i = 1;

    public void add(){
        i++;
        add();
    }

    public static void main(String[] args) throws Exception {
        TestOom oom = new TestOom();
        oom.add();
    }
}

输出结果:

Exception in thread "main" java.lang.StackOverflowError
	at TestOom.add(TestOom.java:19)
	at TestOom.add(TestOom.java:20)
	at TestOom.add(TestOom.java:20)
	at TestOom.add(TestOom.java:20)

StackOverflowError的理解:栈的深度超过了JVM分配给线程的栈的大小时会出现。

/**
 * @author: wayne
 * @desc:
 * @date: 2018/5/10 14:47
 * @version: 1.0
 *   -Xss128K
 */
public class TestOom {

    private void dos(){
        while (true){

        }
    }

    public void add(){
        while (true){
            Thread t = new Thread(new Runnable() {
                public void run() {
                    dos();
                }
            });
            t.start();
        }
    }

    public static void main(String[] args) throws Exception {
        TestOom oom = new TestOom();
        oom.add();
    }
}

输出结果:

机器卡死了,毛线没看到,慎执行。但是最终结果肯定是

java.lang.OutOdMemoryError: unable to create native thread。

OutOdMemoryError的理解:JVM在扩展栈时无法申请到足够的空间。

方法区和运行时常量池溢出

/**
 * @author: wayne
 * @desc:
 * @date: 2018/5/10 14:47
 * @version: 1.0
 *  -Xms20M
-Xmx20M
-Xmn10M
-XX:PermSize=10M
-XX:MaxPermSize=10M
-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/dump/
 */
public class TestOom {

    public static void main(final String[] args) throws Exception {

        while (true){
            Enhancer enhancer = new Enhancer();
            enhancer.setSuperclass(Oom.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,args);
                }
            });
            enhancer.create();
        }

    }
    static class Oom{

    }
}

输出结果:

java.lang.OutOfMemoryError: PermGen space
Dumping heap to /dump/\java_pid3364.hprof ...
Heap dump file created [3331973 bytes in 0.089 secs]
Exception in thread "main" 
Exception: java.lang.OutOfMemoryError thrown from the UncaughtExceptionHandler in thread "main"

方法区存放类的的信息。这些类被回收的条件非常苛刻,因此在大量生产Class的应用中需要注意。

常量池溢出的例子不太好造出来。因为每个版本的常量池放的地方不一样,本例子中使用的都是1.7,报错都是堆内存溢出。

阅读更多
个人分类: jvm
想对作者说点什么? 我来说一句

没有更多推荐了,返回首页

加入CSDN,享受更精准的内容推荐,与500万程序员共同成长!
关闭
关闭