JVM 篇:虚拟机异常

个人感觉使用代码来讲解比纯文字更清晰,如下:

// 虚拟机异常一般为 *Error,常见的有 OutOfMemoryError 和 StackOverflowError
public class JVMError {

    /**
     * JVM options:
     * -Xms1M      将堆的最小值设为 1M
     * -Xmx1M      将堆的最大值设为 1M
     * ps 当堆的最小值和最大值设为一样时,堆的大小是固定的
     * <p>
     * 在 jdk7 下的运行结果为 java.lang.OutOfMemoryError: Java heap space
     * 在 jdk8 下的运行结果为 java.lang.OutOfMemoryError: GC overhead limit exceeded
     */
    static class Instance {}
    private static void heap() {
        List<Instance> list = new LinkedList<>();

		// 原理:不断创建新对象,同时使用 list 保持对其的引用(新对象不会被 GC 回收内存),直至堆内存上限
        while (true) list.add(new Instance());
    }

    /**
     * JVM options:
     * -Xss1K       将栈的大小设为 1K
     * ps 在 HotSpot 中虚拟机栈和本地方法栈是合并在一起的
     * <p>
     * 运行结果为 java.lang.StackOverflowError
     */
    private static void stack() {
        // 原理:使用没有停止条件的递归,该方法永远不会运行结束,运行直至栈深度上限
        stack();
    }

    /**
     * JVM options:
     * -Xss1M       将栈的大小设为 1M
     * ps Win 下的虚拟机中,Java 的线程是映射到操作系统的内核线程的,所以会导致系统假死;
     * ps 理论上这段代码运行后会得到 OutOfMemoryError
     * <p>
     * 运行结果:死机
     */
    private static void stack2() {
        // 原理:不断创建新的线程,同时每个线程都保持方法不退出,因为虚拟机栈是线程私有的,将会不断被分配栈内存,直至栈内存上限
        while (true) {
            Thread thread = new Thread(() -> {
                while (true) ;
            });
            thread.start();
        }
    }

    /**
     * JVM options:
     * -XX:PermSize=1M      永久代大小为 1M
     * -XX:MaxPermSize=1M   永久代最大大小为 1M
     * ps String::intern 使用时会在常量池中检查是否含有当前字符串,如果有则返回该字符串的引用,否则将当前字符串存入常量池
     * <p>
     * 在 jdk7 的运行结果为 java.lang.OutOfMemoryError: PermGen space
     * jdk8 的方法区没有使用永久代来实现,而是元空间,所以上述虚拟机参数无效
     * <p>
     * 这里测试的是 jdk7 之前的方法区的运行时常量池,如果要测试整个方法区,则要不断加载 Class 对象
     * 通常的做法是通过 cglib,为某一个类不断创建子类
     */
    private static void runtimeConstPool() {
        int i = 0;
        List<String> list = new LinkedList<>();
        
        // 原理:不断向运行时常量池中添加常量,同时使用 list 保持对常量的引用,直至方法区内存上限
        while (true) list.add(String.valueOf(i++).intern());
    }

    /**
     * JVM options:
     * -XX:MaxDirectMemorySize=1M       最大直接内存为 1M
     * ps 如果不指定 MaxDirectMemorySize,则最大直接内存的值与 -Xmx 一样
     * ps 使用 Java nio 中的 DirectByteBuffer 的 Unsafe 实例来分配直接内存
     * <p>
     * 在 jdk8 下的运行结果为 java.lang.OutOfMemoryError
     */
    private static void directMemory() throws IllegalAccessException {
        Field field = Unsafe.class.getDeclaredFields()[0];
        field.setAccessible(true);
        Unsafe unsafe = (Unsafe) field.get(null);

		// 原理:不断分配直接内存至上限
        while (true) unsafe.allocateMemory(1024 * 1024);
    }
}

  以上内容为阅读 深入理解Java虚拟机(第2版)后的笔记及对 JDK8 的实践补充。看完这本书后最大的感觉就是,,,再看一遍,很多原来理解不了的知识点就可以看懂了,因为很多内容是前后呼应的。有兴趣的可以去阅读这本书,强推。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值