内存泄漏探讨下(解决方法)
发生内存泄漏,先查再解。检查用 DDMS 里的 Heap,分析用 MAT;日常开发还可以接 LeakCanary,在 debug 包里把 dump 和路径算好。
一、内存泄漏的检查工具 Heap
工欲善其事必先利其器。Heap 用来大致判断有没有泄漏,MAT 用来分析泄漏发生在哪里。开发环境 DDMS 能找到这两个。
具体操作:
-
在 Devices 设备列表里找到设备,点要监控的进程。 -
点 “Update Heap” 更新堆内存。 -
点 “Heap” 视图看内存。 -
每次 Activity 退出和进入时点 “Cause GC”,手动调用 GC。 -
观察 data object 那一行。每次点 Cause GC 看 Total Size,如果不断增大,说明存在泄漏。
先模拟泄漏,再用 Heap 判断。泄漏代码如下:
new Runnable(){} 是非静态匿名内部类,会强引用外围对象 LeakAty。打开方向旋转,不断转屏让 LeakAty 反复创建。没有这段代码时,旧 Activity 会在 onDestroy 之后被回收;有了它,Runnable 一直跑、不会被回收,它强引用的 LeakAty 也不会被回收。转 n 次,内存里就有 n+1 个 LeakAty。
Heap 第一次按 Cause GC:
上图 data object 的 Total Size 为 1.031M。多次旋转后再看:
Total Size 变成 2.059M。每次 GC 后 data object 总大小没有回落,可以证实存在泄漏。泄漏发生在哪,交给 MAT。
二、内存泄漏的分析工具 MAT
MAT 需要 .hprof。通过 “Dump HPROF file” 转存当前堆,保存为 1.hprof。
导出的 1.hprof 要用 ..\sdk\tools\ 下的 hprof-conv.exe 转换,才能被 MAT 导入,转成 out1.hprof。
File → Open Heap Dump… 导入 out1.hprof。
点左边 Overview,Actions → Histogram。
想知道 Activity 有没有泄漏,输入关键词 Activity,回车。
下图搜索结果里 Activity 实例有 7 个。点选中红色框,右键 → Merge Shortest Paths to GC Roots → exclude all phantom/weak/soft etc. references。排除虚引用、弱引用、软引用,剩下都是强引用。
过滤出来的强引用列表里,这七个实例都被 Thread 引用,证实上面的代码确实泄漏。
三、使用 LeakCanary 检测 Android 的内存泄漏
什么是 LeakCanary?为什么选它?
LeakCanary 是 Pierre-Yves Ricau 开发的开源库,用来检测内存泄露。对战泄漏通常要经过:
-
了解 OutOfMemoryError 情况。 -
重现问题。 -
发生泄露时把内存 Dump 出来。 -
分析 dump,定位可疑对象。 -
计算这个对象到 GC roots 的最短强引用路径。 -
确定路径里哪个引用不该有,然后修复。
很复杂。如果有一个库能在 OOM 之前把这些事情做完,你只要修问题就好——LeakCanary 做的就是这件事。可以在 debug 包里轻松检测内存泄露。
| 工具 | 干什么 | 关键动作 |
|---|---|---|
| Heap | 判断有没有泄漏 | Cause GC 后看 data object Total Size 是否只增不减 |
| hprof-conv + MAT | 定位谁握着对象 | Histogram → Merge Shortest Paths to GC Roots(排除弱/软/虚引用) |
| LeakCanary | debug 包自动走完上述步骤 | 你负责修那条不该存在的强引用 |
一句话总结:Heap 看 Total Size 只增不减,MAT 沿强引用找到 GC Root,LeakCanary 则把 dump 和路径计算提前做完,你只负责剪断那条不该有的边。
转载请注明来源:内存泄漏探讨下(解决方法)
















