各区域 OOM(堆、元空间、直接内存、栈)成因、Dump 分析与调优(36-70)

千辰君_5334

千辰君_5334

2026-05-22

1040人浏览

原创

oom本质是jvm某内存区域耗尽且gc无法回收,被迫抛出outofmemoryerror;按堆、元空间、直接内存、栈四大区域,成因、分析路径与调优手段各不相同。

各区域 oom(堆、元空间、直接内存、栈)成因、dump 分析与调优(36-70)

Java 应用发生 OOM,本质是某块 JVM 内存区域耗尽且无法回收,JVM 被迫中止分配并抛出 OutOfMemoryError。不同区域的 OOM 表现不同、成因明确、分析路径清晰、调优手段也各具针对性。下面按堆、元空间、直接内存、栈四个核心区域分别说明。

堆内存溢出(java.lang.OutOfMemoryError: Java heap space)

堆是对象实例的主要存放区,也是 GC 管理的核心。溢出最常见,通常表现为应用运行一段时间后突然卡顿、Full GC 频繁、最终崩溃。

  • 典型成因:对象持续创建未释放(如静态集合缓存、ThreadLocal 持有引用)、内存泄漏(File/Socket/Connection 未 close)、大数组或大集合一次性加载、年轻代过小导致对象频繁晋升至老年代
  • Dump 分析关键点:启用 -XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/dumps/;用 MAT 打开 hprof 文件,查看 Dominator Tree,重点关注占用 Top 的类及其 GC Roots 路径;检查是否有异常增长的集合、未关闭的资源类、重复加载的 classloader 实例
  • 调优方向:确认是泄漏还是容量不足——若 dump 中存在大量本该被回收的对象,优先修复代码;若对象合理但总量大,可适当增大堆(-Xms4g -Xmx4g),同时调整年轻代比例(-XX:NewRatio=2)或 Survivor 区大小,避免过早晋升

元空间溢出(java.lang.OutOfMemoryError: Metaspace)

元空间替代了 JDK 8 以前的永久代,存放类的元数据(类名、字段、方法、常量池等)。溢出不反映在堆内,因此堆 dump 很小却报 OOM,容易误判。

BetterYeah AI
BetterYeah AI

BetterYeah AI是一款面向企业的一站式 AI Agent 应用开发平台。

下载
  • 典型成因:动态代理类爆炸式生成(CGLIB、ASM、Spring AOP 配置不当)、热部署未清理旧 classloader、大量 JSP 编译、自定义类加载器反复加载同一类但未卸载
  • Dump 分析关键点:堆 dump 对元空间帮助有限,需配合 jstat -gc <pid></pid> 观察 MCM/MCU(Metaspace Capacity/Used)增长趋势;用 jcmd <pid> VM.native_memory summary scale=MB</pid> 查看本地内存中 metaspace 占用;必要时加 -XX:NativeMemoryTracking=detail 追踪
  • 调优方向:设置合理上限(-XX:MetaspaceSize=256m -XX:MaxMetaspaceSize=512m)防止无节制扩张;排查代理类生成逻辑,禁用 CGLIB 的 setUseCache(false);确保热部署场景下旧 classloader 能被回收;重启应用可临时缓解(避免类重复加载)

直接内存溢出(java.lang.OutOfMemoryError: Direct buffer memory)

直接内存由 JVM 外部管理(如操作系统 malloc),不受堆大小限制,但受 -XX:MaxDirectMemorySize 或系统物理内存约束。NIO、Netty、RocketMQ 等高频使用 direct buffer 的框架易触发此问题。

  • 典型成因:ByteBuffer.allocateDirect() 调用过多且未显式 clean(如未调用 buffer.clear() 或未释放 Cleaner 引用)、Netty 中 ByteBuf 泄漏、堆外内存池配置过大或未回收
  • Dump 分析关键点:堆 dump 几乎为空或仅含少量 DirectByteBuffer 对象;用 jstat -gc <pid></pid> 观察 CCU(Compressed Class Space Used)和 MCU 无明显变化;更有效的是 jcmd <pid> VM.native_memory detail</pid>,重点关注 “Internal” 和 “Direct Memory” 分区;Linux 下可用 pmap -x <pid></pid> 查看进程总 RSS 是否异常飙升
  • 调优方向:显式限制直接内存上限(-XX:MaxDirectMemorySize=1g);检查 NIO 使用是否遗漏 cleaner.clean() 或 buffer.clear();Netty 应用开启 -Dio.netty.leakDetectionLevel=paranoid 定位泄露点;避免在循环中反复 allocateDirect

栈相关异常(StackOverflowError / OutOfMemoryError: unable to create new native thread)

栈分两类问题:单线程深度递归导致 StackOverflowError;线程数超限导致 unable to create new native thread。后者虽带 OOM 字样,实为操作系统级资源耗尽。

  • 典型成因:无限递归、过深调用链(如 JSON 反序列化深层嵌套对象);线程池无界创建、HTTP 连接未复用、Tomcat maxThreads 设置过高、系统 ulimit -u 限制太小
  • Dump 分析关键点:StackOverflowError 会输出完整异常栈,直接定位递归入口;“unable to create new native thread” 需结合 ps -eLf | grep <pid> | wc -l</pid> 查当前线程数,对比 ulimit -u 值;jstack 输出可观察线程状态(大量 WAITING 或 BLOCKED 可能暗示线程池阻塞)
  • 调优方向:对递归逻辑加深度控制或改用迭代;减小单线程栈大小(-Xss256k)以容纳更多线程;严格管控线程池(设 core/max size、使用有界队列、配置拒绝策略);调高系统级线程上限(ulimit -u 65535);排查连接泄漏(如数据库连接未归还、HTTP client 未 close)

每种 OOM 都对应明确的内存边界与行为特征,抓准现象、配好监控参数、用对分析工具,就能快速收敛根因。调优不是盲目加大内存,而是让资源分配与业务模型匹配。

相关文章

PHP速学视频免费教程(入门到精通)
PHP速学视频免费教程(入门到精通)

PHP怎么学习?PHP怎么入门?PHP在哪学?PHP怎么学才快?不用担心,这里为大家提供了PHP速学教程(入门到精通),有需要的小伙伴保存下载就能学习啦!

下载

相关标签:

本站声明:本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

相关专题

更多
堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5367

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2348

6

堆和栈的区别
堆和栈的区别

堆和栈的区别:1、内存分配方式不同;2、大小不同;3、数据访问方式不同;4、数据的生命周期。本专题为大家提供堆和栈的区别的相关的文章、下载、课程内容,供大家免费下载体验。

2023.07.18

5367

5

堆和栈区别
堆和栈区别

堆(Heap)和栈(Stack)是计算机中两种常见的内存分配机制。它们在内存管理的方式、分配方式以及使用场景上有很大的区别。本文将详细介绍堆和栈的特点、区别以及各自的使用场景。php中文网给大家带来了相关的教程以及文章欢迎大家前来学习阅读。

2023.08.10

2348

6

Kratos框架Protobuf接口定义与代码生成合集
Kratos框架Protobuf接口定义与代码生成合集

本专题讲解Kratos框架接口定义体系,涵盖proto编写规范、proto add/client/server生成命令、http注解路由、validate校验、OpenAPI文档生成、跨服务proto复用与兼容性设计。

2026.10.10

0

15

C++虚函数怎么定义和调用
C++虚函数怎么定义和调用

C++虚函数是实现运行时多态的重要机制。本专题从virtual关键字的基本用法入手,介绍基类与派生类之间的函数重写、基类指针调用派生类方法,以及动态绑定的执行过程,帮助初学者掌握虚函数的核心语法。

2026.10.10

0

26

C++类与对象的封装方法教程
C++类与对象的封装方法教程

C++封装是面向对象编程的核心特性之一,通过类将数据与操作数据的函数组织在一起,并利用访问权限控制外部访问。本专题介绍类的定义、成员变量、成员函数以及public、private和protected的使用方法,帮助初学者掌握封装的基本原理。

2026.10.10

0

32

C++构造函数定义与调用方法
C++构造函数定义与调用方法

C++构造函数用于初始化类对象,是面向对象编程的重要基础。本专题从构造函数的定义、声明和调用入手,介绍默认构造函数、带参数构造函数、拷贝构造函数及成员初始化列表,帮助初学者掌握对象创建与初始化的基本方法。

2026.10.10

0

16

Kratos框架零基础入门教程
Kratos框架零基础入门教程

本专题整理Kratos框架入门内容,涵盖Go环境准备、kratos CLI安装升级、new命令创建项目、目录结构分层说明、服务启动与双协议端口、依赖下载报错排查,帮助开发者快速跑通第一个Kratos框架微服务应用。

2026.10.10

0

15

热门下载

更多
网站特效
/
网站源码
/
网站素材
/
前端模板

精品课程

更多
相关推荐
/
热门推荐
/
最新课程
GDB Reference Card
GDB Reference Card

共0课时 | 0人学习

《Debugging with GDB》用户手册
《Debugging with GDB》用户手册

共0课时 | 0人学习

Valgrind FAQ
Valgrind FAQ

共0课时 | 0人学习