Java--异常情况讨论

堆相关的主要就是堆内存异常,不停的创建对象,并且存在应用指向,比如利用List容器存储下来。

/**
     * -Xms20m -Xmx20m -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=D:\heapdump.hprof
     *
     * 堆内存溢出
     */
    @Test
    public void test01(){
        List<CustomerObj> lst=new ArrayList<>();
        for (int i = 0; i < 1000000; i++) {
            lst.add(new CustomerObj());
        }
        System.out.println("run over");
    }

在d盘下生成文件,用D:\ProgramFiles\Java\jdk1.8.0_144\bin\jvisualvm.exe打开,在概要中显示具体的信息
Java--异常情况讨论_第1张图片
发现CustomerObj实例数过多。
Java--异常情况讨论_第2张图片

栈 相 关 的 异 常 主 要 就 是 栈 容 量 无 法 容 纳 新 创 建 的 栈 帧 , 比 如 调 用 栈 过 深 , \color{#FF0000}{栈相关的异常主要就是栈容量无法容纳新创建的栈帧,比如调用栈过深,}
或 者 方 法 中 变 量 过 多 , 执 行 方 法 时 分 配 的 栈 帧 需 要 更 多 的 容 量 。 \color{#FF0000}{或者方法中变量过多,执行方法时分配的栈帧需要更多的容量。}
肯 定 不 会 出 现 栈 容 量 溢 出 的 问 题 , 因 为 线 程 开 始 执 行 , 即 为 每 一 个 线 程 分 配 了 线 程 独 享 的 栈 内 存 \color{#FF0000}{肯定不会出现栈容量溢出的问题,因为线程开始执行,即为每一个线程分配了线程独享的栈内存} 线线线
方法调用过深导致的StackOverFlowError,往往就是使用到了递归。

    @Test
    public void test02(){
        stackLeaf();
    }

    public void stackLeaf(){
        stackLeaf();
    }

还 有 一 种 情 况 , 在 32 位 的 系 统 上 才 能 出 现 u n a b l e t o c r e a t e n a t i v e t h r e a d , \color{#FF0000}{还有一种情况,在32位的系统上才能出现unable to create native thread,} 32unabletocreatenativethread
因 为 32 位 机 器 给 每 个 进 程 分 配 的 最 大 空 间 才 为 2 G , 导 致 没 有 \color{#FF0000}{因为32位机器给每个进程分配的最大空间才为2G,导致没有} 322G
空 间 为 线 程 创 建 对 应 的 栈 空 间 \color{#FF0000}{空间为线程创建对应的栈空间} 线

方法区和运行常量池
1.7之前常量池在方法区中,1.7后在堆中

    /**
     * -Xmx20m
     * 
     * 常量池溢出
     */
    @Test
    public void test04(){
        String str="";
        List<String> lst=new ArrayList<>();
        for (int i = 0; i < 10000; i++) {
            str=str+i;
            lst.add(str.intern());
        }
        System.out.println("run over");
    }

在1.8中执行得到堆内存溢出。
Java--异常情况讨论_第3张图片
方法区中存储的是类信息,比如类变量、方法,修饰符。如果采用动态代理的形式大量创建类,也会出现溢出,但是在1.8中不会出现。1.8后PermSize和MaxPermSize参数没有用了,因为已经去掉了永久代,改为元空间,

直接空间导致的内存溢出

    /**
     * Unsafe分配空间-导致直接内存OutOfMemory
     * @throws IllegalAccessException
     */
    @Test
    public void test06() throws IllegalAccessException {
        Field unsafeField= Unsafe.class.getDeclaredFields()[0];
        unsafeField.setAccessible(true);
        Unsafe unsafe = (Unsafe) unsafeField.get(null);
        while (true){
            unsafe.allocateMemory(1024*1024);
        }
    }

直接内存溢出和堆内存溢出最大的不同是如果发生了直接内存溢出,heap dump文件中将不会有什么明显的异常。

你可能感兴趣的:(Java)