《Java 100 天进阶之路》第65篇:OOM与内存泄漏排查(2026版)
第65篇OOM与内存泄漏排查2026精版系列导航《Java 100 天进阶之路》完整目录 |⬅️ 上一篇第64篇类加载器与热部署 |➡️ 下一篇第66篇JIT编译与性能优化️ 本文阅读地图3 分钟速览第61~64篇搞定了JVM内存、GC、类加载器但线上OOM来了怎么办本篇直击OOM与内存泄漏排查实战。OOM是Java生产环境的“头号杀手”但排查有章可循模块核心问题一句话回答OOM类型OOM有哪几种Heap Space最常见、Metaspace、Direct Buffer、GC Overhead、Unable to create native thread内存泄漏 vs 内存溢出有什么区别泄漏是“慢慢漏”溢出是“瞬间炸”——泄漏是溢出的最常见原因排查流程怎么查看日志 → jstat监控 → jmap dump → MAT分析 → 修复验证五步闭环核心工具用什么工具jstat实时监控、jmap堆快照、MAT深度分析、Arthas生产在线诊断常见泄漏场景哪里最容易漏静态集合、未关闭资源、ThreadLocal、内部类持有外部引用、类加载器泄漏面试最爱问高频考点有哪些见文末 小节核心原则遇到OOM先看日志确认类型再针对性排查不要一上来就dump堆。一、核心知识点1. 内存泄漏 vs 内存溢出术语英文含义类比内存泄漏Memory Leak已分配的内存无法被GC回收可用内存逐渐减少水龙头没关紧一滴一滴漏迟早水漫金山内存溢出OutOfMemoryError (OOM)内存耗尽JVM无法继续分配对象水缸满了继续加水就会溢出核心关系内存泄漏是内存溢出的最常见原因。排查OOM本质上是排查内存泄漏。2. OOM的五种核心类型OOM类型错误信息根本原因排查方向堆内存溢出Java heap space堆内存不足以容纳对象最常见检查大对象、内存泄漏、堆大小元空间溢出Metaspace类元数据占满元空间检查动态类加载、类加载器泄漏直接内存溢出Direct buffer memoryNIO直接内存堆外耗尽检查Netty/DirectByteBuffer使用GC OverheadGC overhead limit exceededGC回收98%内存却腾不出空间基本等于内存泄漏按泄漏排查线程溢出unable to create new native thread线程数超过系统限制检查线程池配置、线程泄漏快速判断OOM日志是第一手线索先看错误信息中的关键词再决定后续排查方向。二、通俗讲解1分钟开心学把JVM内存想象成一个水缸系统堆内存水缸主体装水对象。漏水内存泄漏时水慢慢减少加水太快大对象暴增时水溢出Heap Space OOM。元空间水缸旁边的“目录架”存书的分类信息类元数据。书太多动态生成类太多时目录架被塞满Metaspace OOM。直接内存水缸外的“管道”水流NIO数据从这里快速通过。管道太窄或堵住DirectBuffer过多水流不畅Direct buffer memory OOM。排查就像修水管看水表看日志确认是哪个区域出了问题。监控水位jstat看水位变化趋势。抽水检查jmap dump把水抽出来看里面有什么。实验室分析MAT找出到底是哪个阀门在漏水。修好阀门修复代码把漏水的根源堵住。三、五步排查流程2026实战版第一步看日志——确认OOM类型# 堆内存溢出 java.lang.OutOfMemoryError: Java heap space # 元空间溢出 java.lang.OutOfMemoryError: Metaspace # 直接内存溢出 java.lang.OutOfMemoryError: Direct buffer memory # GC Overhead基本等于内存泄漏 java.lang.OutOfMemoryError: GC overhead limit exceeded⚠️重要OOM时日志中会明确告诉你是哪种类型先看类型再行动不要盲目操作。第二步jstat——实时监控GC状态# 查看GC状态每秒输出一次共10次jstat-gcutilpid100010# 输出示例S0 S1 E O M CCS YGC YGCT FGC FGCT GCT0.000.0045.2398.7692.3489.12123412.34556745.67858.023快速判断标准O老年代使用率长期 95% →内存泄漏FGCFull GC次数每小时涨几百次 →内存泄漏EEden区频繁满 → 对象分配过快YGC次数多但YGCT很低 → 新生代偏小第三步jmap——生成堆快照# 方式1手动dump生产环境谨慎操作建议低峰期jmap-dump:formatb,file/tmp/heap.hprofpid# 方式2OOM时自动dump推荐生产开启-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/tmp/heap.hprof⚠️重要警告jmap dump时JVM会STWStop-The-World生产环境必须在低峰期操作。推荐配置自动dumpOOM发生时自动生成无需人工介入。OOM自动dump完整配置-XX:HeapDumpOnOutOfMemoryError-XX:HeapDumpPath/var/log/heap.hprof-XX:PrintGCDetails-Xloggc:/var/log/gc.log-XX:UseGCLogFileRotation-XX:NumberOfGCLogFiles10-XX:GCLogFileSize100M第四步MAT——深度分析堆快照1. 导入堆快照将.hprof文件拖入MAT生成“Leak Suspects Report”泄漏检测报告。2. 三大核心视图视图作用使用场景Histogram直方图按类统计实例数和内存占用找出占用内存最多的类Dominator Tree支配树找出保留最多内存的对象根节点定位大对象持有者Path to GC Roots显示对象为何无法被回收的引用链追踪泄漏根源3. 泄漏排查标准流程① 打开Leak Suspects Report红色爆炸图标指向泄漏源头 ② 定位可疑类右键 → Path to GC Roots ③ 选择 exclude all phantom/weak/soft etc. references ④ 找到强引用链定位泄漏代码4. 堆快照损坏的应急处理2026新增高频场景线上dump的hprof文件可能因OOM瞬间进程强制退出、磁盘空间不足等原因被截断。MAT报错HPROF parser encountered a violation时# 临时方案放宽MAT严格模式# Preferences → HPROF Parser → Strictness → 改为 Warning 或 Permissive# 或启动MAT时加参数-DhprofStrictnessWarningtrue⚠️ 强行解析后部分数据会缺失仅应急用正式排查建议重新生成完整堆文件。第五步修复与验证根据MAT分析结果修复代码再次用jstat监控验证泄漏是否已修复。四、常见内存泄漏场景与代码示例场景1静态集合类持有对象// ❌ 错误静态List永不释放publicclassCacheManager{privatestaticListObjectcachenewArrayList();publicvoidadd(Objectobj){cache.add(obj);}// 只增不减}// ✅ 正确使用WeakHashMap或设置缓存上限privatestaticMapString,ObjectcachenewWeakHashMap();// 或使用Caffeine/Guava Cache设置过期时间场景2未关闭的资源// ❌ 错误未关闭连接publicvoidreadFile(Stringpath){FileInputStreamfisnewFileInputStream(path);// 使用fis忘记close}// ✅ 正确try-with-resources自动关闭try(FileInputStreamfisnewFileInputStream(path)){// 使用fis}// 自动关闭场景3ThreadLocal未清理// ❌ 错误线程池中ThreadLocal未removeThreadLocalStringcontextnewThreadLocal();context.set(userId);// 任务结束未调用remove()// 线程池复用 → userId残留且内存泄漏// ✅ 正确try-finally保证removetry{context.set(userId);// 业务逻辑}finally{context.remove();// 必须}特别注意多次热部署后Metaspace持续增长很可能是类加载器泄漏——旧的WebappClassLoader未释放其加载的所有类都无法回收。场景4内部类持有外部类引用// ❌ 错误非静态内部类隐式持有外部类classOuter{classInner{/* 隐式持有Outer.this */}voidmethod(){InnerinnernewInner();// 外部类无法被GC}}// ✅ 正确使用静态内部类staticclassInner{/* 不持有外部引用 */}场景5Druid连接池SQL统计泄漏#Druid配置不当导致SQL统计无限累积 # 错误未限制SQL统计缓存大小# ✅ 正确限制缓存大小关闭不必要的统计spring.datasource.druid:filter.stat.merge-sql:truefilter.stat.slow-sql-millis:5000# 限制连接池监控缓存数量web-stat-filter.session-stat-enable:false五、核心工具链速查工具类型核心命令适用场景jstatJDK内置jstat -gcutil pid 1000实时监控GC判断泄漏趋势jmapJDK内置jmap -dump:formatb,fileheap.hprof pid生成堆快照jhatJDK内置jhat heap.hprof离线分析堆快照Web界面jstackJDK内置jstack pid线程快照排查死锁/阻塞MAT独立工具导入.hprof文件深度泄漏分析、引用链追踪VisualVMJDK内置jvisualvm实时监控、采样分析Arthas阿里开源heapdump、heap、jad生产在线诊断、无需重启工具选型建议开发/测试用VisualVM生产实时监控用jstat深度分析用MAT生产紧急排查用Arthas。六、避坑要点错误/误区后果正确做法遇到OOM第一反应是jmap dump生产环境STW可能引发雪崩先看日志确认OOM类型再行动OOM后暴力扩容加-Xmx掩盖内存泄漏OOM卷土重来先排查泄漏再考虑扩容生产未开启HeapDumpOnOOMOOM后无法分析根因生产环境必须开启MAT解析hprof文件报错就放弃错过排查机会放宽严格模式应急解析jmap dump在生产高峰期执行STW导致接口超时低峰期操作或用自动dumpThreadLocal用完不remove线程池场景内存泄漏try-finally保证remove只看堆内存忽略元空间/直接内存遗漏其他OOM类型根据日志类型针对性排查七、面试高频考点Q1内存泄漏和内存溢出的区别内存泄漏是对象无法被GC回收可用内存逐渐减少内存溢出是内存耗尽JVM无法继续分配对象。内存泄漏是内存溢出的最常见原因。Q2OOM有哪几种常见类型如何排查五种核心类型①Java heap space堆内存溢出→ jstat看GC jmap dump MAT分析②Metaspace元空间溢出→ 检查类加载器泄漏③Direct buffer memory直接内存溢出→ 检查NIO/Netty使用④GC overhead limit exceeded→ 基本等于内存泄漏⑤unable to create new native thread→ 检查线程池配置。Q3生产环境OOM排查的标准流程是什么五步闭环①看日志确认OOM类型②jstat监控GC状态③jmap dump或自动dump生成堆快照④MAT深度分析⑤修复代码并验证。Q4常用的OOM排查工具有哪些①jstat实时GC监控②jmap生成堆快照③MAT深度泄漏分析④VisualVM可视化监控⑤Arthas生产在线诊断。Q5如何防止OOM在生产环境发生① 生产环境强制开启-XX:HeapDumpOnOutOfMemoryError② 开启GC日志③ 配置合理的-Xmx和-Xms④ 代码层面避免静态集合无限增长、资源及时关闭、ThreadLocal及时remove⑤ 定期review和压测。 面试官追问陷阱加分题追问1“MAT分析hprof文件时Path to GC Roots为什么要排除弱引用和软引用” GC Roots路径中弱引用WeakReference和软引用SoftReference在GC时会被回收不会造成内存泄漏。只有强引用链才是泄漏的根本原因。排除弱/软/虚引用后留下的就是真正的泄漏根源。追问2“Metaspace OOM最常见的场景是什么怎么排查” 最常见的是类加载器泄漏——热部署时旧的WebappClassLoader未释放其加载的所有类都无法被GC回收。排查方法用jstat -gc pid看Metaspace使用率持续增长用MAT分析hprof找ClassLoader相关的大对象检查是否有自定义类加载器未正确释放。追问3“OOM自动生成的hprof文件被截断了MAT打不开怎么办” 三种应急方案① 放宽MAT严格模式Preferences → HPROF Parser → Strictness → Warning/Permissive② 添加启动参数-DhprofStrictnessWarningtrue③ 使用其他工具如VisualVM尝试打开。强行解析后部分数据会缺失正式排查建议重新生成完整堆文件。八、练习题分析题某服务jstat显示老年代使用率持续98%以上FGC每小时数百次。这是什么问题下一步应该做什么场景题一个Spring Boot应用频繁热部署后出现OutOfMemoryError: Metaspace分析可能原因和解决方案。代码题下面的代码有什么问题如何修复publicclassUserContext{privatestaticThreadLocalStringuserIdnewThreadLocal();publicstaticvoidsetUserId(Stringid){userId.set(id);}// 使用userId但从未remove}实战题配置生产环境JVM参数要求OOM时自动生成堆快照到/data/dump/heap.hprof并开启GC日志轮转。 你的学习进度当前第65篇 / 共108篇 ·进阶篇JVM调优与故障排查第61~70篇✅ 已完成基础篇44篇 第45~65篇 正在学第65篇⏳ 待学习第66~108篇 完整目录 学习指南 | 订阅本专栏不错过每一篇 下一篇文章预告下一篇《第66篇JIT编译与性能优化》内容简介JIT即时编译器原理、热点代码检测、逃逸分析、栈上分配、锁消除、内联优化以及JVM编译参数调优。JVM调优专题持续深入拿下JIT编译器《Java 100 天进阶之路 | 从入门到上岗就业》每天一篇建议收藏 关注一起100天拿offer 点击关注我更新后第一时间收到推送

相关新闻

基于西门子PLC的自动装瓶机控制系统设计与实现

基于西门子PLC的自动装瓶机控制系统设计与实现

1. 自动装瓶机控制系统设计概述在饮料、药品、日化等行业的包装生产线上,自动装瓶机是最关键的设备之一。传统人工灌装方式不仅效率低下,还容易造成产品污染和计量误差。我们团队基于西门子S7-1200 PLC开发的这套控制系统,实现了从空瓶输送到…

2026/7/31 5:14:39 阅读更多 →
JMeter压力测试实战:从电商下单场景到性能瓶颈定位

JMeter压力测试实战:从电商下单场景到性能瓶颈定位

1. 项目概述:为什么我们需要一个JMeter压力测试案例?如果你是一名后端开发、测试工程师或者运维,那么“压力测试”这个词对你来说一定不陌生。它就像给系统做一次全面的“体能检查”,在用户量激增、大促活动来临前,提前…

2026/7/31 5:14:39 阅读更多 →
【2027最新】基于SpringBoot+Vue的星之语明星周边产品销售网站管理系统源码+MyBatis+MySQL

【2027最新】基于SpringBoot+Vue的星之语明星周边产品销售网站管理系统源码+MyBatis+MySQL

博主介绍:✨ 专业背景 专注Java企业级开发与小程序生态,全网影响力10万开发者,CSDN特邀作者、技术专家、新星计划导师。 🎯 核心服务 📚 毕业设计智库 微信小程序方向:100个前沿选题 Java企业级方向&#x…

2026/7/31 5:14:39 阅读更多 →

最新新闻

练习项目跟进es查询(day10)

练习项目跟进es查询(day10)

es查询代码es_data_router.get("/search", summary"职位搜索") async def search_jobs(# ---------- 关键词 ----------keyword: Optional[str] Query(None, description"搜索关键词,如 Java、前端"),# ---------- 筛选 ----------w…

2026/7/31 5:50:51 阅读更多 →
Android编译失败:全面解析Execution failed for task ‘:app:compileDebugJavaWithJavac‘

Android编译失败:全面解析Execution failed for task ‘:app:compileDebugJavaWithJavac‘

1. 项目概述:当你的Android项目编译突然“罢工” “Execution failed for task ‘:app:compileDebugJavaWithJavac‘”——这行红彤彤的报错信息,对于任何一个Android开发者来说,都再熟悉不过了。它就像一个不请自来的“老朋友”&#xff0c…

2026/7/31 5:50:51 阅读更多 →
企业 AI 落地,第一件事不是买模型,而是建好企业知识库

企业 AI 落地,第一件事不是买模型,而是建好企业知识库

企业 AI 落地,第一件事不是买模型,而是建好企业知识库 大家好,我是老王,一个在技术圈摸爬滚打多年的程序员。这两年,AI 大模型火得不行,到处都在谈“企业 AI 落地”。很多老板二话不说,先砸钱买…

2026/7/31 5:50:51 阅读更多 →
C#异常处理实战指南:从try-catch到全局异常处理

C#异常处理实战指南:从try-catch到全局异常处理

1. 项目概述:为什么异常处理是C#开发的“安全带”干了这么多年C#开发,从桌面程序到Web API,再到各种后台服务,我越来越觉得,异常处理(Exception Handling)就像是程序员给代码系上的“安全带”。…

2026/7/31 5:50:51 阅读更多 →
Unity触控交互开发实战:基于Lean Touch实现物体点击拖拽与缩放

Unity触控交互开发实战:基于Lean Touch实现物体点击拖拽与缩放

1. 项目概述:为什么Unity触控交互值得深究在移动应用和桌面触控一体机大行其道的今天,流畅、直观的触控交互早已不是“加分项”,而是“及格线”。作为一名Unity开发者,你可能已经习惯了用鼠标和键盘在编辑器里“指点江山”&#x…

2026/7/31 5:50:51 阅读更多 →
博途V16中PLC系统时间转字符串的完整实现与优化指南

博途V16中PLC系统时间转字符串的完整实现与优化指南

1. 项目缘起:为什么要在博途中处理系统时间字符串?在工业自动化项目里,尤其是涉及到数据记录、生产报表、设备状态追溯或者配方管理的场景,时间戳是一个绕不开的核心要素。你可能需要把某个报警发生的时间、一批产品的生产开始/结…

2026/7/31 5:49:51 阅读更多 →

日新闻

物理复制比逻辑复制好在哪?数据库复制原理详解

物理复制比逻辑复制好在哪?数据库复制原理详解

数据库复制是把主库数据同步到备库的机制,分为逻辑复制和物理复制两种。逻辑复制传输的是 SQL 语句或行变更事件,物理复制传输的是存储引擎底层的物理日志。阿里云 PolarDB(云原生数据库)采用物理复制,在同步延迟、数据…

2026/7/31 0:00:34 阅读更多 →
BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南

BilibiliDown:3分钟学会B站视频下载的终极指南 【免费下载链接】BilibiliDown (GUI-多平台支持) B站 哔哩哔哩 视频下载器。支持稍后再看、收藏夹、UP主视频批量下载|Bilibili Video Downloader 😳 项目地址: https://gitcode.com/gh_mirrors/bi/Bilib…

2026/7/31 0:00:34 阅读更多 →
有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

有哪些游戏数据AI平台?游戏行业Data+AI融合方案盘点

当前,游戏行业的“DataAI融合”已从概念验证进入价值落地阶段。根据IDC 2025年数据,中国AI游戏云市场规模已达18.6亿元;同时,游戏研发环节AI渗透率高达86%,生成式AI内容普及率超过50%。面对庞大的市场,游戏…

2026/7/31 0:00:34 阅读更多 →

周新闻

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 道路桥梁裂缝检测数据集 道路桥梁病害识别检测数据集

深度学习道路桥梁裂缝检测系统 数据集6000张 完整源码已标注数据集训练好的模型环境配置教程程序运行说明文档,可以直接使用!系统支持图片、视频、摄像头等多种方式检测裂缝,功能强大实用。 1数据集6000张 8各类别

2026/7/31 1:03:03 阅读更多 →
深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

深度学习YOLO模型如何训练 PUBG 绝地求生目标检测数据集

pubg数据集 精选原图1.42万数据 1.49万标签 无任何重复、算法增强或冗余图像! pubg绝地求生目标检测数据集 1分类:e_body,14905个标签,txt格式 共计14244张图,99%为640*640尺寸图像 适合yolo目标检测、AI训练关键词&am…

2026/7/29 14:34:28 阅读更多 →
Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex英雄目标检测数据集 深度学习框架YOLO如何训练APEX数据集

Apex检测数据集数据集详情检测类别: allies enemy tag图片总量:7247张训练集:5139张验证集:1425张测试集:683张标注状态:全部已标注,即拿即用数据格式:支持YOLO格式及其他格式&#…

2026/7/31 4:19:39 阅读更多 →

月新闻