java

关注公众号 jb51net

关闭
首页 > 软件编程 > java > Java OOM异常原理、场景、排查

Java OOM异常从原理、场景、排查到解决方案完全攻略(一文彻底吃透)

作者:皙然

OOM是Java虚拟机在无法分配足够内存以满足程序需求时抛出的严重错误,这篇文章主要介绍了Java OOM异常从原理、场景、排查到解决方案完全攻略的相关资料,文中通过代码介绍的非常详细,需要的朋友可以参考下

前言

在 Java 后端开发里,OOM(OutOfMemoryError) 绝对是线上最让人 “头皮发麻” 的问题之一。它不像普通异常那样好定位,往往服务跑着跑着突然崩掉,日志寥寥几句,让人无从下手。

这篇文章就把 OOM 讲得通透、详细、能直接用于实战,从是什么、为什么、有哪些类型、怎么排查、怎么根治,一次性讲全。

一、什么是 OOM?

OOM 全称 OutOfMemoryError,意思是:JVM 无法为新对象分配内存,且垃圾回收也无法腾出足够空间,最终抛出的致命错误。

重点理解三句话:

  1. OOM 是 Error,不是 Exception,一旦出现,应用基本不可用。
  2. 不是 “内存不够”,而是 内存被占满、且回收不了。
  3. 90% 的 OOM 不是 JVM 内存太小,而是 代码问题。

二、OOM 出现的根本原因

一句话总结:程序不断创建对象 → 对象一直被引用 → GC 无法回收 → 内存被撑爆 → 新对象无处安放 → OOM

常见根源:

三、JVM 内存区域与 OOM 的关系

Java 虚拟机把内存分成不同区域,每个区域都可能 OOM:

  1. Heap 堆:存放对象实例 → 最常见 OOM
  2. Metaspace 元空间:存放类信息、方法、常量、代理类
  3. 虚拟机栈:方法调用栈 → 栈溢出
  4. 本地方法栈:Native 方法使用
  5. 直接内存:NIO 使用的堆外内存
  6. 程序计数器:唯一不会 OOM 的区域

下面我们逐个讲最常出现的 6 种 OOM。

四、6 种最经典 OOM 场景详解

1. 堆内存溢出(Java heap space)

错误信息:

java.lang.OutOfMemoryError: Java heap space

原因:堆内存被占满,不断创建对象,且都被强引用,无法 GC。

典型代码:

List<Object> list = new ArrayList<>();
while (true) {
    list.add(new Object());
}

真实业务场景:

这是 线上最常见的 OOM。

2. 元空间溢出(Metaspace)

错误信息:

java.lang.OutOfMemoryError: Metaspace

原因:加载的 类太多,元空间放不下。

常见场景:

JVM 参数:

-XX:MetaspaceSize=128m
-XX:MaxMetaspaceSize=256m

3. 直接内存溢出(Direct buffer memory)

错误信息:

java.lang.OutOfMemoryError: Direct buffer memory

原因:NIO 使用 ByteBuffer.allocateDirect() 申请的堆外内存耗尽。

常见场景:

4. 栈溢出(StackOverflowError)

错误信息:

java.lang.StackOverflowError

原因:方法调用层级太深,栈帧数量超过栈最大深度。

典型代码:

public void loop() {
    loop(); // 无限递归
}

业务场景:

5. 无法创建本地线程

错误信息:

java.lang.OutOfMemoryError: unable to create new native thread

原因:每个线程都占用栈内存,线程数超出系统限制。

场景:

6. GC 开销超限

错误信息:

java.lang.OutOfMemoryError: GC overhead limit exceeded

原因:JVM 98% 的时间在做 GC,却只回收不到 2% 内存,进入 “累死状态”。

本质:内存快空了,又不断产生垃圾。

五、内存泄漏 vs 内存溢出

这是面试 + 实战必考点。

1. 内存溢出(OOM)

2. 内存泄漏(Memory Leak)

最常见泄漏场景:

六、线上 OOM 标准排查流程

第一步:必须开启 OOM 自动 dump(重中之重)

在 JVM 启动参数里加:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/logs/heap.hprof

OOM 时会自动导出内存快照,这是定位问题的关键。

第二步:分析 dump 文件

工具:

重点看 4 点:

  1. 哪个类的对象最多
  2. 谁在引用这些对象
  3. 是不是业务对象(是 → 代码问题)
  4. GC Roots 链在哪里

第三步:配合命令行工具定位

jstat -gc 进程ID 1000 10   # 看GC情况
jmap -heap 进程ID          # 看堆配置
jmap -histo 进程ID         # 看对象数量
arthas-boot.jar            # 阿里Arthas,一键排查

判断内存泄漏最简单方式:每次 Full GC 后,内存水位不下降 → 100% 内存泄漏

七、OOM 通用解决方案

1. 代码层面(根治)

2. JVM 参数优化

-Xms2g -Xmx2g              # 堆初始值和最大值
-XX:MetaspaceSize=256m
-XX:MaxMetaspaceSize=256m
-XX:+HeapDumpOnOutOfMemoryError

3. 架构层面

八、总结(一句话记住 OOM)

到此这篇关于Java OOM异常从原理、场景、排查到解决方案的文章就介绍到这了,更多相关Java OOM异常原理、场景、排查内容请搜索脚本之家以前的文章或继续浏览下面的相关文章希望大家以后多多支持脚本之家!

您可能感兴趣的文章:
阅读全文