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

为何捕获StackOverflowError时会出现1024重复输出的异常情况?

为什么捕获StackOverflowError后会重复打印栈长度?

咱们来一步步拆解这个问题。你写的代码逻辑是想通过触发栈溢出获取默认栈大小,但结果和预期不符,核心问题出在栈溢出发生时JVM的异常处理机制和栈状态的稳定性上。

先梳理两种场景:

  • 注释main第一行:递归调用直到栈满,抛出StackOverflowError,catch块执行一次,输出1024,符合预期。
  • 不注释第一行:先输出1,然后一堆1024连在一起输出,和预期的1 1024不符。

问题根源

当你执行new Exception().getStackTrace().length时,这行代码远不止看起来那么简单:它会调用Exception的构造方法、getStackTrace()方法,还有JVM内部用于收集栈轨迹的native方法,这些操作都会在调用栈中额外创建多个栈帧。这就导致后续递归调用的栈溢出点提前到来,栈的剩余空间比注释第一行时少很多。

当递归触发StackOverflowError进入catch块后,你调用err.getStackTrace().length来获取栈轨迹长度——但这里的坑是:getStackTrace()方法本身需要JVM遍历当前调用栈来生成StackTraceElement数组,而此时栈已经处于接近溢出的临界状态。遍历栈的过程中,JVM需要创建临时的栈帧来执行相关操作,这会再次触发StackOverflowError!

更关键的是,这个新抛出的StackOverflowError会被同一个catch块捕获(因为当前线程的执行点就在catch块内),导致catch块中的System.out.println被反复执行,直到栈空间被彻底耗尽、线程无法继续执行为止。这就是你看到一堆1024连在一起输出的原因。

而当你注释掉main方法的第一行时,初始栈是空的,递归能达到更深的层次才溢出。此时栈溢出发生时,JVM有足够的剩余栈空间来处理getStackTrace()调用,不会再次触发溢出,所以catch块只执行一次,输出单个1024。

验证思路

如果你想验证这个结论,可以修改catch块的代码,去掉getStackTrace()的调用,直接打印一个固定值,比如:

catch(StackOverflowError err){
    System.out.println("test");
}

这时候不管是否注释main第一行,你都会看到只输出一次test(或者极少数几次,取决于栈的剩余空间),因为没有了getStackTrace()这个会触发二次溢出的操作。

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

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.05.28 09:58:35