Wrayの知识库 Wrayの知识库
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
首页
  • Java 基础
  • Java 集合
  • Java 并发
  • Java IO
  • JVM
  • Spring Framework
  • Spring Boot
  • Spring Cloud
  • Spring Security
  • MySQL
  • Redis
  • 计算机基础
  • 操作系统原理
  • Linux
  • MacOS
  • Windows
  • 系统工程与研究专题
  • AI 基础
  • 大模型基础
  • Prompt 工程
  • RAG 检索增强生成
  • Agent 智能体
  • AI 应用开发
  • AI 工程化
  • AI 安全与治理
  • AI 面试与设计题
  • 纸质书
  • 电子书
  • 学习课程
疑难杂症
GitHub (opens new window)
  • Java章节编写规范
  • Java基础

  • Java集合

  • Java并发

  • Java IO

  • JVM

    • JVM概述
    • JVM基础

    • 类加载机制

    • 运行时内存

    • 垃圾回收

    • 执行引擎与优化

    • 工具与问题排查

      • JVM参数
      • JDK命令行工具
      • jstack线程分析
      • jmap与堆转储分析
      • jcmd与JFR
      • CPU飙高排查
      • 内存泄漏排查
        • 1. 什么是 Java 内存泄漏
        • 2. 常见泄漏来源
        • 3. 观察趋势
        • 4. 生成堆转储
        • 5. MAT 分析思路
        • 6. ThreadLocal 泄漏
        • 7. 缓存泄漏
        • 8. 阶段小结
        • 9. 泄漏排查流程图
        • 10. 泄漏模式速查
        • 11. Tips 快问快答
      • 频繁Full GC排查
    • 调优实践与面试

目录

内存泄漏排查

Java 有 GC,但仍然会内存泄漏。Java 内存泄漏通常不是对象无法回收,而是对象仍然被不该存在的引用链持有。

# 1. 什么是 Java 内存泄漏

Java 内存泄漏指对象已经没有业务意义,但仍然可以从 GC Roots 到达,因此无法被 GC 回收。

典型表现:

  • 老年代持续增长。
  • Full GC 后内存下降不明显。
  • 最终 OOM。
  • 服务运行时间越长越慢。

# 2. 常见泄漏来源

常见来源:

  • 静态集合。
  • 本地缓存无淘汰。
  • ThreadLocal 未 remove。
  • 监听器未注销。
  • 连接、Session、Channel 未关闭。
  • 类加载器泄漏。
  • 大对象被全局引用。
  • 队列生产快于消费。

# 3. 观察趋势

先看趋势,而不是立刻 dump。

关注:

  • 堆使用量是否持续上升。
  • Full GC 后是否能回到稳定水位。
  • 老年代是否持续增长。
  • 对象数量是否持续增加。
  • 泄漏是否和某个接口或任务相关。

如果 Full GC 后仍回不去,泄漏嫌疑较大。

# 4. 生成堆转储

jmap -dump:format=b,file=heap.hprof <pid>

更推荐配置 OOM 自动 dump:

-XX:+HeapDumpOnOutOfMemoryError
-XX:HeapDumpPath=/data/dump

如果条件允许,取两个不同时间点的 dump 对比更有价值。

# 5. MAT 分析思路

使用 MAT 时重点看:

  • Leak Suspects。
  • Dominator Tree。
  • Retained Size。
  • Path to GC Roots。
  • 类实例数量。

不要只看 Shallow Size。一个小对象可能持有一棵巨大的对象树。

# 6. ThreadLocal 泄漏

ThreadLocal 常见泄漏模式:

threadLocal.set(value);
// 忘记 remove

线程池中的线程长期存活,如果不清理 ThreadLocal,值对象可能一直被线程持有。

建议:

try {
    threadLocal.set(value);
    // business
} finally {
    threadLocal.remove();
}

# 7. 缓存泄漏

缓存不是 Map 加静态变量这么简单。

缓存应有:

  • 最大容量。
  • 过期策略。
  • 淘汰策略。
  • 指标监控。
  • 命中率统计。

生产建议使用成熟缓存库,例如 Caffeine。

# 8. 阶段小结

Java 内存泄漏的本质是“不该活着的对象还能从 GC Roots 到达”。排查时先看趋势,再抓 dump,最后沿引用链找到持有者。修复通常不是加堆,而是切断错误引用或增加生命周期管理。

# 9. 泄漏排查流程图

发现内存持续增长
  │
  ├─ 看 GC 后水位是否回落
  │
  ├─ 回落正常
  │   └─ 可能是正常波动或负载增加
  │
  └─ 不回落
      ├─ 抓 heap dump
      ├─ MAT 看 Retained Size
      ├─ 找 GC Roots 引用链
      ├─ 对应到代码持有者
      └─ 修复生命周期

# 10. 泄漏模式速查

模式 典型代码味道 修复方向
静态集合 static Map 不清理 生命周期管理
ThreadLocal set 后不 remove finally remove
缓存 无容量、无过期 Caffeine/淘汰策略
监听器 注册后不注销 close/unregister
队列 无界队列 背压、限流、有界队列
类加载器 热部署后旧 loader 可达 清理线程、驱动、ThreadLocal

# 11. Tips 快问快答

Q:内存上涨就是泄漏吗?

A:不一定。要看 Full GC 后水位是否能回落,以及是否和流量/缓存预期一致。

Q:弱引用能防止所有泄漏吗?

A:不能。错误使用弱引用可能隐藏问题,value 或其他链路仍可能强引用对象。

Q:怎么判断缓存是不是泄漏?

A:看是否有明确容量、过期、淘汰和命中率。如果没有边界,就有泄漏风险。

Q:泄漏修复后怎么验证?

A:压测或灰度观察 GC 后水位、对象数量、老年代趋势是否稳定。

上次更新: 2026/06/24, 16:03:01
CPU飙高排查
频繁Full GC排查

← CPU飙高排查 频繁Full GC排查→

Copyright © 2023-2026 Wray | 鄂ICP备2024050235号-1
  • 跟随系统
  • 浅色模式
  • 深色模式
  • 阅读模式