StackOverFlowError 和 OutOfMemoryError 的区别

StackOverflowErrorOutOfMemoryError 都是 JVM 抛出的严重错误,接下来我们简单看一下他们的区别。

StackOverFlowError:栈内存不够深(线程调用 栈深度 超出限制)。

OutOfMemoryError:目标内存区域不够大(堆、方法区等共享内存区域 容量耗尽,无法为新对象分配足够空间)。

关于 JVM 的组成部分,大家可以看下这篇博文:JVM的组成部分

一、StackOverFlowError:栈溢出

1、定义

单个线程的方法调用栈深度超出 JVM 允许的最大值 时,虚拟机栈无法再创建新的栈帧,触发此错误。

2、原因

  • 方法调用链过长(如 无限递归、深层递归);
  • 单个 栈帧过大(如方法内定义了超大的局部变量数组)。

3、场景

  • 最典型:无终止条件的递归调用(方法反复调用自身,栈帧持续叠加)。
public class StackOverFlowTest {
    // 递归调用,无终止条件
    public static void recursiveCall() {
        recursiveCall(); // 方法自身调用,栈帧不断入栈
    }

    public static void main(String[] args) {
        recursiveCall(); 
        // 运行结果:Exception in thread "main" java.lang.StackOverflowError
    }
}
  • 深层 嵌套 调用(如 A 调用 B,B 调用 C,… 嵌套 10000+ 层)。

二、OutOfMemoryError(OOM):内存不足

1、定义

某块共享内存区域(堆、元空间等)容量耗尽,且 GC 无法回收足够内存 时,JVM 无法为新对象分配空间,触发此错误。

2、原因

  • 内存泄漏(无用对象被 GC Root 引用,无法回收,持续占用内存);
  • 内存分配 过小(如堆内存 -Xmx 设置过小,无法满足业务对象创建需求);
  • 超大对象 直接超出内存限制(如创建 new byte[1024*1024*1024],超出堆最大容量)。

内存泄漏 可参考此博文 Java 哪些情况会导致内存泄漏

3、场景

  • 堆内存 OOM:创建大量对象且无法被 GC 回收(如静态集合持有对象)。
  • 元空间 OOM:动态生成大量类(如 Spring / CGLIB 动态代理、频繁加载类文件),元空间(存储类信息)耗尽。
  • 栈内存 OOM(与 StackOverFlowError 不一样):创建大量线程(每个线程占用独立栈内存),总栈内存超出物理内存限制(不是单个线程栈深度,而是线程数量过多)。

一般来说,StackOverflowError 的错误日志会包含 java.lang.StackOverflowError + 方法调用栈(at XXX.XXX.method(...))OutOfMemoryError 的错误日志会有 Java heap space、Metaspace、Direct buffer memory 等标注,这些信息便于我们直接定位。

StackOverflowError 像是 一条单行道上的车排得太长,堵死了(栈帧太多)。

OutOfMemoryError 像是 一个停车场停满了车,再也没有空位(堆空间不足)。

当服务出现 StackOverflowError 或者 OutOfMemoryError 时,服务会处于 不稳定 状态,甚至会自动关闭,此时,我们需及时排查原因。

同为万里江湖客,共见三生风月身。-- 烟沙九洲

posted @ 2025-12-29 19:33  烟沙九洲  阅读(3)  评论(0)    收藏  举报