【深入理解java虚拟机v3】代码清单2-4 、2-5虚拟机栈和本地方法栈测试

1. 前言

测试环境64 位 win7 + JDK1.8

-Xss 限制虚拟机栈的大小
-Xoss 限制本地方法栈大小

由于HotSpot虚拟机不区分虚拟机栈和本地方法栈,对于HotSpot来说,-Xoss参数虽然存在,但是没有实际效果,栈容量只能由-Xss来设置。

在《虚拟机规范》中描述了两种异常:

  • 如果在线程请求的栈深度大于虚拟机所允许的最大深度,将抛出StackOverflowError异常
  • 如果虚拟机的栈内存允许动态扩展,当栈容量无法申请到足够的内存时,将抛出OutOfMemoryError异常

需要注意的是,虽然规范允许虚机设置是否支持扩展,但是Hotspot是选则不支持扩展的。并且由于不支持扩展,理论上就不存在运行期间出现内存溢出的情况,除非创建线程时,首次申请内存时报内存溢出,也就是说Hotspot只会报栈溢出!

本文的目的就是验证Hotspot只会报栈溢出!

2. 虚拟机栈深度报错

思路:通过-Xss限制单个栈内存的大小,这里我们限定为为128K,当然128K也是32位windows下 jdk6一般的默认大小。如果是64位windows系统下的jdk11,则会提示不能低于180K,而这个值在linux下则可能是228K,如果低于这些值,那么在启动的时候会报错。

代码清单2-4:

注意设置-Xss128k,限定了栈的上限,因此很快就报错

/**
 * VM Args:-Xss128k
 *
 * @author zzm
 */
public class JavaVMStackSOF_1 {

    private int stackLength = 1;

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

    public static void main(String[] args) throws Throwable {
        JavaVMStackSOF_1 oom = new JavaVMStackSOF_1();
        try {
            oom.stackLeak();
        } catch (Throwable e) {
            System.out.println("stack length:" + oom.stackLength);
            throw e;
        }
    }
}

执行结果,与书上相差不大:

stack length:2401
Exception in thread "main" java.lang.StackOverflowError
	at org.fenixsoft.jvm.chapter2.JavaVMStackSOF_1.stackLeak(JavaVMStackSOF_1.java:13)

栈的上限约是2401个,说明栈不能无限的深度,在递归或调用方法层次时,注意深度!

3. 栈帧申请内存不够报错

栈是由栈帧组成的,栈帧的个数就是栈的深度,可以自定百度栈帧的定义。栈帧又由局部变量表、操作数栈等构成,因此,如果增加局部变量表的长度(也就是局部变量的个数),那么单个栈帧的体积就变大,由于总容量是不可扩容的,因此,深度就会变少。

下面就来验证上述理论:

代码清单2-5:

定义了大量的本地变量,增大此方法帧中本地变量表的长度。本例中是100个long类型的变量,提前耗尽内存。

注意:没有限制栈的大小,不设置-Xss

/**
 * VM: JDK 1.0.2, Sun Classic VM
 *
 * @author zzm
 */
public class JavaVMStackSOF_3 {
    private static int stackLength = 0;

    public static void test() {
        long unused1, unused2, unused3, unused4, unused5, unused6, unused7, unused8, unused9, unused10, unused11, unused12, unused13, unused14, unused15, unused16, unused17, unused18, unused19, unused20, unused21, unused22, unused23, unused24, unused25, unused26, unused27, unused28, unused29, unused30, unused31, unused32, unused33, unused34, unused35, unused36, unused37, unused38, unused39, unused40, unused41, unused42, unused43, unused44, unused45, unused46, unused47, unused48, unused49, unused50, unused51, unused52, unused53, unused54, unused55, unused56, unused57, unused58, unused59, unused60, unused61, unused62, unused63, unused64, unused65, unused66, unused67, unused68, unused69, unused70, unused71, unused72, unused73, unused74, unused75, unused76, unused77, unused78, unused79, unused80, unused81, unused82, unused83, unused84, unused85, unused86, unused87, unused88, unused89, unused90, unused91, unused92, unused93, unused94, unused95, unused96, unused97, unused98, unused99, unused100;

        stackLength++;
        test();

        unused1 = unused2 = unused3 = unused4 = unused5 = unused6 = unused7 = unused8 = unused9 = unused10 = unused11 = unused12 = unused13 = unused14 = unused15 = unused16 = unused17 = unused18 = unused19 = unused20 = unused21 = unused22 = unused23 = unused24 = unused25 = unused26 = unused27 = unused28 = unused29 = unused30 = unused31 = unused32 = unused33 = unused34 = unused35 = unused36 = unused37 = unused38 = unused39 = unused40 = unused41 = unused42 = unused43 = unused44 = unused45 = unused46 = unused47 = unused48 = unused49 = unused50 = unused51 = unused52 = unused53 = unused54 = unused55 = unused56 = unused57 = unused58 = unused59 = unused60 = unused61 = unused62 = unused63 = unused64 = unused65 = unused66 = unused67 = unused68 = unused69 = unused70 = unused71 = unused72 = unused73 = unused74 = unused75 = unused76 = unused77 = unused78 = unused79 = unused80 = unused81 = unused82 = unused83 = unused84 = unused85 = unused86 = unused87 = unused88 = unused89 = unused90 = unused91 = unused92 = unused93 = unused94 = unused95 = unused96 = unused97 = unused98 = unused99 = unused100 = 0;
    }

    public static void main(String[] args) {
        try {
            test();
        } catch (Error e) {
            System.out.println("stack length:" + stackLength);
            throw e;
        }
    }
}

执行结果,栈深度仅为359就耗尽内存:

stack length:359
Exception in thread "main" java.lang.StackOverflowError
	at org.fenixsoft.jvm.chapter2.JavaVMStackSOF_3.test(JavaVMStackSOF_3.java:33)

4. 总结

由上面2个例子,可以看到,一般情况下,hotspot只会报栈溢出

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值