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

为何Java中斐波那契递归未触发StackOverflowError?

为什么递归阶乘触发StackOverflowError但斐波那契却没有?

我最近测试Java的StackOverflowError时写了这段代码:

package recursion_still_not_working;
public class Main {
    public static void main(String[] args) {
        // System.out.println(fibonacci(50));
        System.out.println("Result: " + factorial(3000));
    }
    public static long fibonacci(long n) {
        if (n > 1) {
            //System.out.println("calculating with " + (n - 1) + " + " + (n - 2));
            return fibonacci(n - 1) + fibonacci(n - 2);
        } else {
            return n;
        }
    }
    public static long factorial(long n) {
        if (n > 1) {
            System.out.println("calculating with " + n);
            return n * factorial(n - 1);
        }
        System.out.println("base case reached: " + n);
        return n;
    }
}

我本来以为调用fibonacci(50)和factorial(3000)都会触发栈溢出,但实际只有阶乘方法报错,斐波那契却能正常运行。我猜测是不是JVM做了什么隐藏优化,对斐波那契递归生效但阶乘无效?我的JVM版本是:openjdk 11.0.3 2019-04-16 OpenJDK Runtime Environment (build 11.0.3+7-Ubuntu-1ubuntu218.04.1) OpenJDK 64-Bit Server VM (build 11.0.3+7-Ubuntu-1ubuntu218.04.1, mixed mode, sharing)


嘿,这个问题其实核心点你可能没注意到——两种递归的实际栈深度差得太远了!

先给你拆解清楚:

  • 你调用的factorial(3000)是一条“直线型”递归:从3000一路调用到1,每一层调用都会在栈里留下一个栈帧,直到最后才开始释放。这一下就堆了3000个栈帧,直接超出了JVM默认栈的承受范围。
  • 而fibonacci(50)虽然看起来递归分支多(有2^50个节点),但栈的深度只看最长的那条调用链——也就是从50降到1的那条,总共才50层。其他分支的调用在返回后就立刻释放了栈空间,根本不会累积下来。

64位OpenJDK Server VM的默认栈大小大概是1MB左右,每层栈帧也就几百字节,50层完全没问题,但3000层直接就爆栈了。

至于你猜的JVM隐藏优化,其实不是主要原因:

  • 首先,阶乘的写法不算尾递归——因为最后一步是n * 递归结果,不是直接返回递归调用,所以JVM没法把它优化成循环(尾递归优化的核心就是把递归转成循环,避免栈累积)。而斐波那契的递归也不是尾递归,所以不存在针对它的特殊优化。
  • HotSpot VM确实有一些动态优化比如栈上替换,但50层的递归深度根本轮不到触发这些优化,就已经顺利执行完了。

你可以自己验证一下:把斐波那契的参数改成10000,你会发现它也会触发StackOverflowError——这就说明本质就是递归深度的问题,不是什么针对性优化在搞鬼。


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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.13 08:11:23