stackoverflowerror 是因递归调用导致栈帧持续累积、超出线程栈空间限制而抛出的错误。其根源在于jvm每调用一次方法就压入一个栈帧,仅在返回时弹出;若递归无终止条件或深度过大,栈帧线性增长直至填满由-xss指定的固定栈内存,且该问题与堆内存和gc无关。

因为每次递归调用都会在栈中创建一个新栈帧,而栈空间是有限的。
栈帧会持续累积,无法释放
Java 方法调用基于栈结构:每进入一次方法(包括递归调用自身),JVM 就压入一个栈帧,保存参数、局部变量、返回地址等;只有方法返回时,该栈帧才弹出。递归没有终止条件或深度过大时,栈帧只进不出,数量线性增长,很快填满分配给该线程的栈空间。
每个线程的栈大小是固定且受限的
JVM 为每个线程分配的栈内存由 -Xss 参数控制(如默认 512KB 或 1MB)。这个值决定了最多能容纳多少层调用。例如:
- 若每层递归占用 1KB 栈空间,-Xss1m 最多支持约 1000 层调用;
- 斐波那契递归(未优化)调用深度接近输入值,
fibonacci(10000)几乎必然溢出; - 即使单次调用不深,但多层嵌套 + 大量局部变量,也会加速耗尽栈空间。
栈溢出不是堆内存问题,无法靠 GC 解决
栈内存由线程独占、自动管理,不经过垃圾回收器。StackOverflowError 是 JVM 检测到“栈深度超限”或“无法分配新栈帧”时主动抛出的错误,与堆内存是否充足无关。哪怕堆还有几GB空闲,只要当前线程栈满了,就会立即失败。
递归本身不是问题,失控的调用链才是根源
合理递归(如二分查找、树的深度遍历)通常几十到几百层,完全安全。真正触发溢出的是:
- 缺失或错误的 base case(基准条件);
- 递归逻辑导致调用次数远超预期(如朴素斐波那契的指数级分支);
- 间接递归(A→B→C→A)未被察觉,形成隐式无限循环。











