stackoverflowerror是栈空间耗尽所致,主因是无限递归或栈帧过大;outofmemoryerror是堆/元空间/直接内存不足所致,需据错误信息细分定位;二者发生时机、排查方式及jvm参数均不同。

看到堆栈信息里的 OutOfMemoryError: Java heap space 或 StackOverflowError,别急着调参数。关键要从错误提示本身快速锁定区域和线索。
看异常类型直接定位内存区域
不同异常对应不同内存区,这是第一步判断依据:
- java.lang.OutOfMemoryError: Java heap space → 堆内存问题:对象分配失败,大概率是内存泄漏或堆配置过小;
- java.lang.StackOverflowError → 栈溢出:通常由无限递归、深层嵌套调用引起,和 -Xss 设置、代码逻辑强相关;
- java.lang.OutOfMemoryError: Metaspace → 元空间满:类加载过多,常见于热部署、动态生成类(如 CGLIB、Groovy)、大量第三方 jar;
- java.lang.OutOfMemoryError: Direct buffer memory → 直接内存超限:ByteBuffer.allocateDirect() 使用失控,Netty、NIO 框架中较常见。
抓堆栈末尾的触发点代码行
异常堆栈最底部(即最后一行)往往指向问题源头:
- 比如 at com.example.service.UserService.loadAllData(UserService.java:87),说明第 87 行可能在一次性查库加载全量数据;
- 又如 at com.example.util.JsonUtils.toJson(JsonUtils.java:42),结合上下文可能是大对象反复序列化导致堆膨胀;
- 若末尾是 at java.base/java.util.ArrayList.add(ArrayList.java:460),且前面连续多层同名方法调用,就要怀疑是否静态 List 不断 add 而未清理。
结合 JVM 参数交叉验证
光看异常不够,得确认当前运行环境是否“先天不足”:
- 用 jps 找到进程 PID,再用 jinfo -flags
查看实际生效的 -Xmx、-Xss、-XX:MaxMetaspaceSize 等值; - 如果日志报堆溢出,但 -Xmx 只有 512m,而业务需缓存数万订单对象,那不是 bug 是配置失当;
- 若报 StackOverflowError,但 -Xss=128k,而方法里定义了多个 MB 级数组——这属于单帧过大,和递归无关,需改写逻辑或调大 -Xss。
辅助日志与工具联动看趋势
单次异常是快照,持续监控才能发现模式:
- 加参数 -XX:+PrintGCDetails -Xlog:gc*:gc.log,观察 GC 日志中老年代使用率(O 列)是否长期 >95%,Full GC 频繁却回收甚少 → 典型内存泄漏信号;
- 用 jstat -gcutil
2000 每 2 秒刷一次,看 O(Old)和 M(Metaspace)是否持续攀升; - 配合 jstack
抓线程快照,若大量线程卡在同一个递归方法里,基本可断定是 StackOverflowError 的根因。











