为什么会抛出StackOverFlowError

img

看上图的样子,程序应当是在堆内存中不断分配空间,不断创造引用,最后导致堆空间不足,进一步产生问题,最终报出OutOfMemoryError。但真实结果却是,报的栈溢出。不知道自己在虚拟机内存这块的理解上是不是有问题。

img

解释:

题主只考虑到了堆上的问题,以为上面的操作只涉及堆,其实栈也是要的

Java在解释执行的时候采用的是栈式的架构, 方法调用、方法内的局部变量都是在栈空间申请的,如果这一块空间不够用了就会产生StackOverflowError。

当然,对象的创建肯定是要堆内存的,如果堆不够用了,那就OutOfMemoryError。

所以题主的代码就是跑的时候既要消耗栈,也要消耗堆,如果是栈先不够用了就抛出StackOverflowError,如果是堆先不够用了就抛出OutOfMemoryError,显然题主的代码是栈先不够用了。

所以要想让它抛出OutOfMemoryError,只需要在栈用完之前先把堆用完即可。

题主的Test对象太小了(具体多小我也不知道,反正不够大),下面代码中一个Test对象至少要10M,所以弄不了几个堆就会用完:

public class Test {
    byte[] data = new byte[10 * 1024 * 1024]; // 注意这两行的
    private Test test = new Test();           // 位置不能颠倒
    public static void main(String[] args) {
        Test test = new Test();
    }
}

img

栈溢出抛出StackOverflowError错误,出现此种情况是因为方法运行的时候栈的深度超过了虚拟机容许的最大深度所致。

对于栈内存溢出,根据《Java 虚拟机规范》中文版:如果线程请求的栈容量超过栈允许的最大容量的话,Java 虚拟机将抛出一个StackOverflow异常;如果Java虚拟机栈可以动态扩展,并且扩展的动作已经尝试过,但是无法申请到足够的内存去完成扩展,或者在新建立线程的时候没有足够的内存去创建对应的虚拟机栈,那么Java虚拟机将抛出一个OutOfMemory 异常。

题主的例子中递归调用了构造函数,故导致StackOverflowError

posted @ 2023-03-19 15:21  哩个啷个波  阅读(48)  评论(0编辑  收藏  举报