StackOverflowError是Error而非Exception,表明JVM栈空间耗尽,无法捕获,必须从代码逻辑或JVM配置解决;核心方法为修复递归出口、减少栈帧体积、合理设置-Xss参数,并通过堆栈快照定位无限递归或深层调用链。

StackOverflowError 不是异常,而是 错误(Error),说明 JVM 栈空间已彻底耗尽,无法再分配新栈帧。它不能被 try-catch 捕获处理,必须从代码逻辑或 JVM 配置层面根本解决。核心改法就三类:改代码、调参数、查根源。
一、优先检查并修复递归或深层调用逻辑
这是 90% 以上 StackOverflowError 的真正原因——不是内存不够,而是调用没出口。
- 确认所有递归方法都有明确、可达的终止条件,且每次递归都向该条件推进(例如
n > 0时才继续,n--后必达 0) - 避免隐式递归:比如重写
toString()、equals()或hashCode()时意外调用自身或相互调用 - 对深度不确定的递归(如树遍历、表达式求值),改用显式栈(Stack替代,把调用栈从线程栈转移到堆内存
- 检查 A→B→C→…→A 这类循环调用链,尤其在代理、AOP、序列化场景中容易出现
二、减少单个栈帧的内存占用
即使调用不深,一个方法里声明超大数组或大量局部变量,也可能让单个栈帧“撑爆”栈空间。
分析 Java Spring Boot 后端 Controller 代码,自动生成 Markdown 格式的接口文档。当用户说“生成 Java 接口文档”、“生成 API 文档”、“从 Spring 代码生成文档”时触发。
- 避免在方法内直接声明大数组(如
new byte[1024 * 1024]),改用 堆上分配(正常 new)或流式处理 - 精简局部变量:合并临时变量、及时复用 Slot(JVM 局部变量表按 Slot 计量,long/double 占 2 个 Slot)
- 将复杂计算逻辑拆分为多个小方法,分散栈帧压力,而非堆在一个方法里塞满变量和逻辑
三、合理调整 JVM 线程栈大小(-Xss)
这是兜底手段,不是首选。盲目加大可能掩盖问题,还可能因线程数多导致总内存超标(总栈内存 = 线程数 × -Xss)。
- 先用
jstack或启动时加-XX:+PrintGCDetails观察典型栈深度(看报错堆栈里重复层数) - 默认值因平台而异(Linux 通常 1MB,Windows 约 320KB),可尝试
-Xss512k或-Xss1m测试 - 高并发服务(如 Web 容器)创建数千线程时,反而建议 适当减小 -Xss(如 256k),同时确保单线程逻辑轻量
四、辅助定位:别只看报错,要看堆栈快照
错误信息末尾的堆栈片段就是关键线索:
- 如果全是同一个方法反复出现(如 1000 行都是
parseExpr()),基本锁定无限递归 - 如果是一长串不同方法(A→B→C→D→…→Z),说明是深层嵌套调用,需检查调用链设计
- 如果报错出现在
String.valueOf()、ArrayList.toString()等基础方法里,大概率是对象 toString() 引发了循环引用










