You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

为何连续调用递归方法时能填充更多栈空间?

栈溢出测试中栈深度逐步递增的现象解析

嘿,这个问题挺有意思的!我之前也碰到过类似的情况,本质上和JVM的栈空间管理、JIT编译优化脱不了干系。先把你的代码补全成可运行的版本方便理解:

public class StackDepthTest {
    int reached = 0;

    private void fillStackToAlmostDead() {
        for (int i = 0; i < 10; i++) {
            try {
                reached = 0;
                exhausting(-1, null);
            } catch (StackOverflowError e) {
                System.out.println(String.format("Filled with %d calls", reached));
            }
        }
    }

    private void exhausting(int depth, Callable<?> after) {
        if (depth < 0) reached += 1;
        if (depth != 0) exhausting(depth - 1, after);
        // 这里省略的逻辑不影响核心递归行为
    }

    public static void main(String[] args) {
        new StackDepthTest().fillStackToAlmostDead();
    }
}

接下来给你拆解为啥会出现深度逐步增加的情况:

  • 栈溢出后的空间释放与复用:第一次触发StackOverflowError时,JVM会把栈帧逐层展开(unwind),释放大部分栈空间。但这里有个关键点:第一次递归时,栈可能还没完全扩展到-Xss160k的上限——JVM的栈是动态增长的,不是一开始就分配满160k。后续的递归调用会逐步把栈“撑”到设定的最大值,自然能容纳更多的递归次数。

  • JIT编译的优化加持:当循环执行几次后,HotSpot的JIT编译器会盯上exhausting这个递归方法,对它进行优化。比如把局部变量分配得更紧凑,或者把某些参数放到寄存器里,减少每个栈帧的内存占用。栈帧变小了,同样的栈空间就能容纳更多的递归调用,深度自然就上去了。

  • 栈空间的阈值边界:当栈真正被撑到-Xss160k的硬上限时,后续的递归就没法再增加深度了,此时你会看到输出的调用次数稳定在同一个数值。

简单说就是:前几次调用是在“试探”栈的可用空间,加上JIT优化帮着省内存,所以深度越来越高,直到触碰到栈的物理上限为止。

内容的提问来源于stack exchange,提问作者Derongan

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.05.25 08:35:46