为什么可以从StackOverflowError中恢复?

2022-08-31 10:14:09

我很惊讶,即使在Java中发生StackOverflowError之后,它也可以继续执行。

我知道这是类错误。类 Error 被降级为“Throwable 的子类,指示合理的应用程序不应尝试捕获的严重问题”。StackOverflowError

这听起来更像是一个建议,而不是一个规则,它假设像StackOverflowError这样的错误实际上是允许的,这取决于程序员的合理性不这样做。看,我测试了这个代码,它正常终止。

public class Test
{
    public static void main(String[] args)
    {
        try {
            foo();
        } catch (StackOverflowError e) {
            bar();
        }
        System.out.println("normal termination");
    }

    private static void foo() {
        System.out.println("foo");
        foo();
    }

    private static void bar() {
        System.out.println("bar");
    }
}

这怎么可能?我认为当StackOverflowError被抛出时,堆栈应该已经满了,以至于没有空间调用另一个函数。错误处理块是否在不同的堆栈中运行,或者这里发生了什么?


答案 1

当堆栈溢出并引发时,通常的异常处理会展开堆栈。放卷堆栈意味着:StackOverflowError

  • 中止当前活动函数的执行
  • 删除其堆栈帧,继续执行调用函数
  • 中止调用方的执行
  • 删除其堆栈帧,继续执行调用函数
  • 等等...

...直到捕获异常。这是正常的(事实上,必要的),并且与引发哪个异常以及为什么引发无关。由于您在第一次调用之外发现了异常,因此填充堆栈的数千个堆栈帧已全部展开,并且大部分堆栈都可以再次免费使用。foo()foo


答案 2

当抛出 StackOverflowError 时,堆栈已满。但是,当它被捕获时,所有这些调用都已从堆栈中弹出。 可以正常运行,因为堆栈不再溢出 s(请注意,我不认为 JLS 保证您可以从这样的堆栈溢出中恢复。foobarfoo


推荐