最新下载
热门教程
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
如何分析堆快照中的“保留大小”快速定位最耗费内存的代码对象
时间:2026-07-26 17:33:55 编辑:袖梨 来源:一聚教程网
保留大小(Retained Size)指删除该对象后GC可回收的内存总量,反映其真实内存占用;MAT中需关闭“Keep unreachable objects”并使用支配树分析,结合GC Roots路径与业务逻辑判断是否泄漏。
什么是保留大小(Retained Size)?
保留大小不是对象自身占多少字节,而是「删掉它,能顺带让 GC 回收多少内存」。比如一个 HashMap 实例的 retained size 很大,往往意味着它持有的键值对、内部数组、以及这些值又引用的下游对象(如 String、ArrayList)全都没法被回收——这才是真正卡住内存的“根因”。浅层大小(shallow size)只算对象头和字段指针,容易误判;深层大小(deep size)把所有引用对象都算进来,但包含可能被其他路径强引用的对象,干扰定位。
MAT 中按 Retained Size 排序时必须关掉“Keep unreachable objects”
默认打开这个选项会导致分析结果里混入大量已不可达、本该被 GC 却还没清理的对象(比如刚被置为 null 但 GC 尚未运行),它们的 retained size 是 0 或极小,却会挤占列表顶部,掩盖真正的问题对象。操作路径是:Preferences → Memory Analyzer → Keep unreachable objects → 取消勾选。做完这一步再打开堆快照,点击列头 Retained Heap 排序,前 10 名才可信。
看“支配树(Dominator Tree)”比看“直方图(Histogram)”更准
直方图只按类名统计实例数和总 shallow size,对排查泄漏几乎没用;而支配树强制体现“谁 hold 住谁”的唯一支配关系,每个节点的 retained size 是它自己 + 所有被它唯一支配的对象之和。关键操作:Open Query Browser → Java → Dominator Tree。重点关注三类节点:
- 非 JDK 内部类(如
com.example.service.CacheManager)排在前列 - 集合类(
ArrayList、ConcurrentHashMap)的retained size远大于其shallow size - 同名类多个实例分散在不同路径,但合计
retained size占堆 15% 以上
点开对象后重点看 “Path to GC Roots” 里的“with all references”
右键某个高 retained size 对象 → Path to GC Roots → with all references。这里暴露的是它为什么活下来:如果路径里出现 java.lang.Thread.localMap,说明是 ThreadLocal 泄漏;如果出现 static 字段(如 MyClass.CACHE),说明静态缓存没做淘汰;如果出现 org.apache.catalina.loader.WebappClassLoader,基本锁定是 Web 应用未正确卸载导致 ClassLoader 泄漏。注意过滤掉 WeakReference 和 SoftReference 路径——它们不阻止 GC,不用优先处理。
真正难的不是找到大对象,而是确认它是否“该活”。同一个 ConcurrentHashMap 实例,如果是业务缓存且设置了 LRU 和过期策略,retained size 大是合理的;但如果它的 key 是不断 new 出来的 StringBuilder,value 是未关闭的 InputStream,那它就是泄漏源。得结合代码上下文判断,不能只盯数字。
相关文章
- 晴空双子500关通关阵容推荐 晴空双子传说级T0阵容搭配与实战解析 07-30
- 辉光之城1907好玩吗 辉光之城1907核心玩法与新手入门指南 07-30
- 未定事件簿主线第十八章行至黎明(上)即将开放 07-30
- 晴空双子爬塔阵容搭配指南 晴空双子高效率通关塔层阵容推荐 07-30
- 生存33天本周礼包码(1月12日) 07-30
- 原神月之四版本全新圣遗物介绍 07-30