为什么 java 递归调用函数可以 运行 永远即使 StackOverflowError?

Why java recursively calling function can run forever even though StackOverflowError?

我在 Java 考试中遇到了以下问题,为什么在递归调用函数后可以 运行 永远,即使 WhosebugError?

public class Solution {
    static int i = 0;

    public static void f(){
        System.out.println(i++);
        try {
            f();
        } catch (WhosebugError e) {
            System.out.println(e);
            f();
        }
    }

    public static void main(String[] args) {
        f();
    }
}

我无法理解为什么 JVM 在我耗尽所有调用堆栈内存后仍然可以 运行? 有没有参考资料,比如JVM规范或者JVM源码,可以解释以上现象?

我既不是 java 也不是 jvm 专家,但我认为添加额外的 recursive depth 输出可以准确显示调用堆栈的情况。

public class Solution {
  static int i = 0;

  public static void f(int depth) {
    System.out.println(i++);
    System.out.println(String.format("depth=%d", ++depth));
    try {
      f(depth);
    } catch (WhosebugError e) {
      System.out.println(e);
      f(depth);
    }
  }

  public static void main(String[] args) {
    f(1);
  }
}

在我的测试中,典型的输出是

...more
java.lang.WhosebugError
161735
depth=3745
161736
depth=3746
161737
java.lang.WhosebugError
161738
java.lang.WhosebugError
161739
java.lang.WhosebugError
161740
depth=3744
161741
depth=3745
...more

WhosebugError 被抛出是因为 jvm 正在考虑堆栈内存的大小限制(默认为 1M?),但是异常被捕获,所以递归没有停止,它仍然尝试调用, jvm 丢弃最近的 1 或 2 个有问题的调用,然后尝试继续,因此 depth 值一次又一次地围绕相同的最大值。

我认为这样 OP 就可以毫无问题地理解为什么 i 正在增加。 我已经耗尽了调用堆栈内存 -- 你还没有,你几乎耗尽了,但是 jvm 总是清除最近的几个调用以避免耗尽。