当前位置: 首页
前端开发
如何分析堆快照中的“保留大小”快速定位最耗费内存的代码对象

如何分析堆快照中的“保留大小”快速定位最耗费内存的代码对象

热心网友 时间:2026-04-24
转载

如何分析堆快照中的“保留大小”快速定位最耗费内存的代码对象

如何分析堆快照中的“保留大小”快速定位最耗费内存的代码对象

免费影视、动漫、音乐、游戏、小说资源长期稳定更新! 👉 点此立即查看 👈

什么是保留大小(Retained Size)?

说到内存分析,很多人第一反应是看对象自己有多大。但这里有个更关键的概念:保留大小。它衡量的不是对象自身占了多少字节,而是回答一个更实际的问题——如果把这个对象从内存里“连根拔起”,能顺带释放出多少空间?

举个例子,一个 HashMap 实例的 retained size 如果特别大,那事情就很有意思了。这意味着,不仅仅是这个 HashMap 对象本身,它里面装的所有键值对、支撑这些键值对的内部数组,甚至这些值对象下游引用的整个对象网络(比如一堆 StringArrayList),全都因为它的存在而“活”着,GC 动不了它们。这才是真正卡住内存脖子的那个“关键先生”。

相比之下,浅层大小(shallow size)只算对象头和字段指针,太表面,容易误判;深层大小(deep size)倒是把引用链上的都算进来了,但它有个问题:会把那些被其他路径强引用的对象也算进去,干扰我们定位真正的“罪魁祸首”。

MAT 中按 Retained Size 排序时必须关掉“Keep unreachable objects”

打开 MAT 分析堆快照,直接按 Retained Heap 排序,你以为排在前面的就是“元凶”?先别急,这里有个常见的坑。

默认情况下,MAT 会勾选“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 → Ja va → Dominator Tree。打开后,重点关注以下几类节点:

  • 排在前列的,是非 JDK 的内部业务类,比如 com.example.service.CacheManager
  • 集合类(像 ArrayListConcurrentHashMap)的 retained size 如果远大于其自身的 shallow size,说明它肚子里“装”了很多东西。
  • 有时候,泄漏不是单个实例造成的,而是多个同类的实例“分头作案”。如果某个类的多个实例分散在不同路径,但它们的 retained size 合计超过了堆的 15%,那也值得高度警惕。

点开对象后重点看 “Path to GC Roots” 里的“with all references”

找到 retained size 大的对象只是第一步。接下来要问:它为什么能活着?是谁在“保”它?

这时候,右键点击这个可疑对象,选择 Path to GC Roots → with all references。这条路径会清晰地告诉你,是什么引用链让它依然坚挺地留在堆里。

路径里透露的信息往往是破案的关键:

  • 如果出现了 ja va.lang.Thread.localMap,那基本可以断定是 ThreadLocal 使用不当导致的内存泄漏。
  • 如果路径指向了一个 static 字段(比如 MyClass.CACHE),那问题很可能出在静态缓存没有设置合理的淘汰机制上。
  • 如果看到了 org.apache.catalina.loader.WebappClassLoader 这类类加载器,那几乎可以锁定是 Web 应用热部署或卸载时,ClassLoader 泄漏的经典场景。

当然,也要注意过滤噪音。查看时可以排除 WeakReferenceSoftReference 这类引用路径——它们本身不阻止 GC,通常不是优先处理的目标。

话说回来,最难的部分往往不是找到那个“大块头”,而是判断它该不该这么大。同一个 ConcurrentHashMap 实例,如果它是业务核心缓存,并且设计了完善的 LRU 和过期策略,那么 retained size 大是合理的,是功能需要。但如果发现它的 key 是不断新创建的 StringBuilder,value 里还挂着一堆未关闭的 InputStream,那它无疑就是内存泄漏的源头。所以,最终一定要结合代码的业务上下文来做判断,不能光盯着数字下结论。

来源:https://www.php.cn/faq/2339684.html

游乐网为非赢利性网站,所展示的游戏/软件/文章内容均来自于互联网或第三方用户上传分享,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系youleyoucom@outlook.com。

同类文章
更多
Less如何提升CSS维护性_使用参数化Mixin实现灵活组件

Less如何提升CSS维护性_使用参数化Mixin实现灵活组件

Less参数化Mixin:如何写出既灵活又可控的样式代码? Less参数化Mixin怎么写才不重复造轮子 开门见山,参数化Mixin的核心目标不是炫技,而是解决一个实际问题:把那些“可能会变”的样式值抽离出来。这样一来,样式规则只需定义一次,修改时就能全局生效,维护效率自然就上去了。关键在于,你得准

时间:2026-04-24 21:53
Vue 中的 Patch 过程是怎么工作的?从 VNode 到真实 DOM 的转化全指南

Vue 中的 Patch 过程是怎么工作的?从 VNode 到真实 DOM 的转化全指南

Vue 中的 Patch 过程是怎么工作的?从 VNode 到真实 DOM 的转化全指南 Patch 的核心目标:高效更新 DOM 简单来说,Vue 的 Patch 过程干的就是一件“聪明事”:它拿着新旧两份虚拟节点(VNode)清单,只去更新真实 DOM 里真正变了的那部分,而不是不管三七二十一,

时间:2026-04-24 21:52
CSS如何实现移动端加载占位骨架屏_利用CSS渐变色与动画效果

CSS如何实现移动端加载占位骨架屏_利用CSS渐变色与动画效果

CSS如何实现移动端加载占位骨架屏:利用渐变色与动画效果 先明确一个核心概念:一个真正好用的骨架屏,本质上不是图片,而是用CSS背景渐变“画”出来的容器轮廓。关键在于,如何让background-image精准覆盖真实内容区域,同时巧妙地利用透明间隙来模拟文字或头像的留白。这听起来简单,但实际操作时

时间:2026-04-24 21:52
CSS如何实现侧边栏推拽切换_利用CSS动画平滑过渡布局

CSS如何实现侧边栏推拽切换_利用CSS动画平滑过渡布局

侧边栏推拽用 transform: translateX() 更流畅,避免 left margin-left 触发重排;初始隐藏用 translateX(-100%),配合 ease-out 或自定义 cubic-bezier 过渡更自然;移动端需谨慎 preventDefault() 并启用 -w

时间:2026-04-24 21:51
Ionic 7 中在 Tab 内实现页面内导航的完整教程

Ionic 7 中在 Tab 内实现页面内导航的完整教程

Ionic 7 中在 Tab 内实现页面内导航的完整教程 本文详解如何在 Ionic 7(Vanilla JS)中为单个 Tab 配置独立的嵌套路由系统,解决 ion-router 在 ion-tab 内无法正常跳转的问题,并提供可运行的结构化实现方案。 如果你正在用 Ionic 7 的纯 Ja v

时间:2026-04-24 21:51
热门专题
更多
刀塔传奇破解版无限钻石下载大全 刀塔传奇破解版无限钻石下载大全
洛克王国正式正版手游下载安装大全 洛克王国正式正版手游下载安装大全
思美人手游下载专区 思美人手游下载专区
好玩的阿拉德之怒游戏下载合集 好玩的阿拉德之怒游戏下载合集
不思议迷宫手游下载合集 不思议迷宫手游下载合集
百宝袋汉化组游戏最新合集 百宝袋汉化组游戏最新合集
jsk游戏合集30款游戏大全 jsk游戏合集30款游戏大全
宾果消消消原版下载大全 宾果消消消原版下载大全
  • 日榜
  • 周榜
  • 月榜
热门教程
更多
  • 游戏攻略
  • 安卓教程
  • 苹果教程
  • 电脑教程