内存泄漏排查
外观
内存泄漏排查[编辑 | 编辑源代码]
内存泄漏(Memory Leak)是指程序中已动态分配的堆内存由于某种原因未能被正确释放,导致系统内存被无效占用,最终可能引发内存溢出(OOM)或性能下降。在JVM中,内存泄漏通常表现为对象不再被使用但仍被GC Roots引用,无法被垃圾回收器回收。
核心原理[编辑 | 编辑源代码]
内存泄漏的本质是可达性分析失效。根据JVM规范,对象被判定为可回收需满足:
典型泄漏场景包括:
- 静态集合长期持有对象引用
- 未关闭的资源(如数据库连接、文件流)
- 监听器未注销
- 线程池未清理
排查工具[编辑 | 编辑源代码]
工具 | 作用 | 适用场景 |
---|---|---|
jmap | 生成堆转储快照 | 离线分析 |
jvisualvm | 可视化内存监控 | 实时观察 |
Eclipse MAT | 内存分析 | 深度诊断 |
Arthas | 在线诊断 | 生产环境 |
基础排查步骤[编辑 | 编辑源代码]
1. 使用jps
获取目标进程ID
2. 生成堆转储文件:
jmap -dump:format=b,file=heap.hprof [pid]
3. 使用MAT分析.hprof
文件
代码示例[编辑 | 编辑源代码]
典型静态集合泄漏案例:
public class LeakExample {
private static List<byte[]> cache = new ArrayList<>();
public void addToCache() {
// 每次添加1MB数据且永不释放
cache.add(new byte[1024 * 1024]);
}
}
输出表现:
java.lang.OutOfMemoryError: Java heap space at LeakExample.addToCache(LeakExample.java:6)
高级分析技巧[编辑 | 编辑源代码]
支配树分析[编辑 | 编辑源代码]
在Eclipse MAT中使用Dominator Tree视图: 1. 查找占用内存最大的对象 2. 检查其引用链 3. 定位非必要引用
引用链追踪[编辑 | 编辑源代码]
关键引用类型:
- 强引用:直接导致泄漏
- 软/弱引用:通常合规
- 虚引用:不影响回收
生产环境案例[编辑 | 编辑源代码]
案例背景:某电商系统每日凌晨出现OOM,重启后恢复。
排查过程: 1. 添加JVM参数收集OOM时的堆转储:
-XX:+HeapDumpOnOutOfMemoryError -XX:HeapDumpPath=/tmp
2. MAT分析显示OrderProcessor
类中的ConcurrentHashMap
持续增长
3. 最终发现是未清理已完成订单的引用
修复方案:
// 原错误代码
completedOrders.put(orderId, order);
// 修正后
completedOrders.remove(orderId); // 处理完成后立即移除
预防措施[编辑 | 编辑源代码]
- 定期进行代码审查,重点关注:
** 集合使用情况 ** 资源关闭操作 ** 监听器注销
- 使用工具自动化检测:
** FindBugs/SpotBugs静态分析 ** JaCoCo覆盖率检查资源释放路径
页面模块:Message box/ambox.css没有内容。
生产环境建议设置内存使用阈值告警,如通过JMX监控 MemoryUsage.getUsed() |