原文作者:Google Android Developers 文档贡献者(页面无个人署名)。中文翻译与技术整理:未完纪。核验日期:2026-10-05。

堆转储记录的是某一时刻应用中的对象及其引用关系。它能帮助我们找出谁占用了内存、哪些对象本应结束生命周期却仍然存活,以及哪些分配行为可能导致掉帧、卡顿甚至崩溃。应用连续使用一段时间后再采样尤其有价值:一些缓慢积累的泄漏,启动时未必看得出来。本文按 Android Developers 当前页面翻译整理,分析对象是托管堆及界面能关联的原生内存信息。
为什么需要分析应用内存
Android 提供托管内存环境。系统判断对象不再使用时,垃圾回收器会把不用的内存归还给堆。虽然垃圾回收机制一直在改进,所有 Android 版本在某些阶段仍需要短暂停下应用代码;多数情况下,这种暂停难以察觉。
如果应用分配内存的速度超过系统回收的速度,就可能等待回收器腾出足够空间。等待会造成跳帧和可见的迟缓。即使前台操作尚未变慢,泄漏的内存也可能在应用进入后台后继续被保留,增加整个系统的内存压力和不必要的 GC。系统最终可能终止应用进程以回收内存,用户返回应用时就需要重新启动进程。
本文采用 Android Studio 提供的堆采集与分析工具。其他观察方式包括命令行 dumpsys,以及 Logcat 中的垃圾回收事件;它们可以补充背景信息,但不替代这里的对象引用分析。
采集堆转储:先明确采样时机
在 Profiler 中用 “run app as debuggable (complete data)” 方式启动应用,选择 “Analyze Memory Usage (Heap Dump)” 任务采集堆。不同 Studio 版本的入口文字可能略有不同,应以当前任务面板为准。
转储期间 Java 内存用量可能暂时升高。这是正常现象,因为转储工作发生在应用自己的进程中,收集数据本身也需要内存。因此,不能把采集瞬间的增长直接判定为业务泄漏。如果需要把采样精确放在某个代码执行点,原文提供了调用 Android Debug.dumpHprofData() 的方式;这里不加入可直接写入用户目录的示例。
从类列表读懂内存指标
| 指标 | 含义与使用方式 |
|---|---|
| Allocations | 堆中的分配数量,用来判断某类对象是否不断积累。 |
| Native Size | 该对象类型关联的原生内存总量,单位为字节。部分 Java 对象也会占用原生内存,例如 Bitmap。Android 7.0 以下设备不显示这一列。 |
| Shallow Size | 该对象类型本身占用的 Java 内存总量,单位为字节。 |
| Retained Size | 由于此类全部实例的存在而被保留的内存总量,单位为字节。它强调对象对其他内存的保留关系。 |
先用 heap 菜单缩小观察范围。默认的 App heap 是应用分配内存的主要堆;Image heap 是系统启动映像,包含启动时预加载的类,这些分配不会移动或消失;Zygote heap 则来自 Android 创建应用进程时使用的写时复制堆。
排列方式可以选 “Arrange by class”,按类名分组;也可以选 “Arrange by package”,按包名分组。类过滤器默认 “All classes”,包含库和依赖;“Show project classes” 只保留项目定义的类;“Show activity/fragment leaks” 则显示 Studio 认为可能存在 Activity 或 Fragment 泄漏的类。最后一个选项是诊断线索,仍需结合对象生命周期核实。
沿实例、字段和引用寻找保留路径
单击类名后,Instance 面板列出具体实例。Depth 是从任一 GC root 到该实例的最短跳数;Native Size 表示该实例占用的原生内存,仅 Android 7.0 及以上可见;Shallow Size 是该实例自己的 Java 内存;Retained Size 则表示它在支配树中所支配的内存大小。
继续单击实例,Instance Details 会展示 Fields 和 References。Fields 列出实例自身的字段;References 列出指向 Instance 面板当前高亮对象的引用。常见字段和引用类型包括结构化对象、数组以及 Java 基本类型。右击某个字段或引用,可以跳转到关联实例,或相关源代码行。
编辑补充:一个实例保留的内存很大,并不自动说明它泄漏了。应用仍然需要的图片缓存、当前 Activity 或业务状态,也可能合理保留大量对象。关键问题是:它的预期生命周期是否已经结束,为什么仍有从 GC root 可达的引用,以及在重复进入退出同一场景后是否持续积累。
识别重复位图
从 Android Studio Narwhal 4 开始,Heap Dump 视图可以识别冗余位图。打开 Profiler,选择 Heap Dump 或 Analyze Memory Usage,开始记录以获取当前内存快照。
在分析结果中寻找黄色警告三角形:Studio 用它标记被重复存储的位图。也可以在 Profiler 顶部的 “Filter by” 选择 “Duplicate Bitmaps”。单击被标记的项目,打开 Bitmap Preview,直接确认重复的究竟是哪张图像。随后回到代码,查找重复加载的路径,并改进缓存策略。
重复位图是可以减少内存占用的线索,但不等同于 Activity 泄漏。应先确认这些副本的用途与生命周期,再决定是否共享、复用或调整缓存。图像预览也可能包含应用中的敏感内容,导出分析材料时应注意访问范围。此处属于编辑补充。
查找 Activity、Fragment 和 Compose 泄漏
最快的入口是类过滤器中的 “Show activity/fragment leaks”。Android Studio 会列出它认为可能说明应用 Activity 或 Fragment 实例泄漏的类。在使用单 Activity 架构的 Compose 应用中,可能没有 Fragment 可筛选;但宿主 Activity 的泄漏仍然关键,因为它会把整个 Compose 层级以及活跃的状态树一起保留在内存中。
手工排查时,可以在类和实例列表中优先查看 Retained Size 较大的对象,并重点检查以下保留关系。
- 生命周期较长的对象持有 Activity 或 Context,连带保留 ComposeView 及其子组合项构成的组合图。
- Jetpack Compose 的 MutableState、状态持有者,或捕获了 Context 的 lambda 没有按预期释放。
- DisposableEffect 的 onDispose 中遗漏了监听器或观察者的注销。
- 非静态内部类(例如某些 Runnable)隐式持有 Activity 实例。
- 缓存保留对象的时间超出实际需要。
找到候选对象后,用 Instance Details 里的 Fields 与 References 继续追到有意义的实例或代码位置。修复应针对延长生命周期的具体引用,而不是仅为了让数字变小而盲目清空所有缓存。
原文还说明,从 Android Studio Panda 开始,Profiler 提供独立的 LeakCanary 集成任务,可把泄漏分析从测试设备移到开发机。文档称这有助于改善分析性能;本文没有对其速度进行实测,也没有把它与手动堆分析混为同一流程。
用重复场景触发并复查问题
为了观察泄漏,需要让相关代码路径运行足够久。应用持续使用后,泄漏对象可能逐渐出现在分配列表顶部;泄漏越小,往往越需要更长时间才能看清趋势。
一个实用场景是在不同 Activity 状态下反复横竖屏切换。如果异步操作或状态持有者保存了 Activity 或 Context,旋转造成的 Activity 重建就可能暴露旧实例被保留的问题,Compose UI 与关联状态树也会一并留下。另一类场景是在不同页面或状态下切到其他应用,或返回主屏幕,再切回当前应用。
原文建议可结合 App Crawler 或 UI Automator 开展 UI 测试。编辑整理的复查顺序是:固定触发步骤,观察应结束生命周期的对象,修复引用关系,再用相同步骤重复采样。本文没有运行这些工具,也没有声称某个示例应用已修复。
导出、导入及旧 HPROF 工具路径
在 Profiler 的 Past Recordings 页签中可以导出或导入堆转储,Android Studio 保存的录制文件扩展名是 .hprof。堆快照可能包含实际业务数据、字符串和图像,编辑建议仅在受控位置保管,不把真实用户快照直接加入公开仓库。
原文保留了使用其他分析器(例如 jhat)的兼容路径:如果分析器要求 Java SE HPROF 格式,需要用 Android SDK 的 platform-tools 目录中的 hprof-conv,把 Android 格式转换为 Java SE 格式。两个参数分别是原始文件和输出文件路径:
hprof-conv heap-original.hprof heap-converted.hprof
版本说明:这一段是原文的旧工具兼容说明,不能据此假定当前 JDK 仍提供 jhat,或任意 SDK 安装中都有相同工具。主要操作路径应采用当前 Android Studio 的分析界面;确需转换时,先核对本机工具是否存在、目标分析器的格式要求,并使用独立输出文件保留原始证据。这里未执行转换命令。
本次静态审核的边界
本页没有嵌入需要运行的应用实现,唯一命令是本地 HPROF 格式转换。静态检查未发现硬编码凭证、命令注入输入或外部上传步骤;采样会增加进程内存,堆快照可能含敏感内容,转换会写入输出文件,这些是实际需要控制的影响。未对设备、Studio 版本、采样开销或泄漏检测结果做执行测试。没有发现其他问题不等于不存在漏洞。
来源、署名与许可
除另有说明,Android Developers 页面内容采用 CC BY 4.0,代码示例采用 Apache 2.0;Google 及相关贡献者保留署名。本文为中文翻译整理,新增诊断边界与旧工具版本提示。
- 原文:Capture a heap dump
- Android 内容许可
- CC BY 4.0
- Apache 2.0
- Debug.dumpHprofData API
- Android 内存管理概述
- Manage your app memory
- dumpsys 工具
- LeakCanary in Android Studio Profiler
- UI Automator
- Capture a heap dump(Views 补充页面)
保留作者与适用许可证。本文调整与安全补充均已说明,未执行原文应用代码或命令。












暂无评论内容