Android 内存泄漏工具使用分析
最近的一次事件让我对 Android 开发中内存泄漏重视起来,平时只忙着开发新的功能,往往会忽略掉内存,cpu 等方面的使用情况,然而遇到 内存泄露或者ANR 问题就要彻底解决,由于Android设备规格不一,好一些的设备上不会出现问题,在一些低端的设备上就会出现各种问题,所以平时也要注意内存泄漏和 cpu 使用问题.
内存泄漏(memory leak)
A memory leak is a particular type of unintentional memory consumption by a computer program where the program fails to release memory when no longer needed. This condition is normally the result of a bug in a program that prevents it from freeing up memory that it no longer needs.This term has the potential to be confusing, since memory is not physically lost from the computer. Rather, memory is allocated to a program, and that program subsequently loses the ability to access it due to program logic flaws.
看不懂 pass。。。知道有这么回事就可以了
初步判断
现象判断
从现象入手,如果肉眼能看出页面卡顿,那肯定是有问题的,首先,尝试连续多次打开应用,观察界面卡顿,动画现象,并截取 log,观察 log 中的 GC 输出
日志,频繁打印GC日志,说明系统频繁触发GC来释放内存,初步推断可能存在内存泄漏,具体使用 DDMS HEAP 工具分析,以下有介绍
内存命令分析
前期可以通过一些 ADB 命令来简单查看下内存相关信息,做初步判断,有一次在项目中发现,开启/关闭某个模块,观察内存状态,竟然差了4M,果断修复。
查看内存系统信息
adb shell cat proc/meminfo
➜ ~ adb shell cat proc/meminfo
MemTotal: 2052484 kB
MemFree: 1450748 kB
Buffers: 23212 kB
Cached: 342548 kB
SwapCached: 0 kB
Active: 338056 kB
Inactive: 203652 kB
Active(anon): 175960 kB
Inactive(anon): 6912 kB
Active(file): 162096 kB
Inactive(file): 196740 kB
..
查看某一应用占用内存
adb shell dumpsys meminfo + packageName
e.g: adb shell dumpsys meminfo com.dangbeimarket
➜ ~ adb shell dumpsys meminfo com.whiskeyfei.tab
Applications Memory Usage (kB):
Uptime: 16199425 Realtime: 16199425
** MEMINFO in pid 14522 [com.whiskeyfei.tab] **
Pss Private Private Swapped Heap Heap Heap
Total Dirty Clean Dirty Size Alloc Free
------ ------ ------ ------ ------ ------ ------
Native Heap 3474 3356 0 0 15475 15475 13196
Dalvik Heap 2861 2788 0 0 3156 2561 595
Dalvik Other 340 328 0 0
Stack 104 104 0 0
Other dev 5 0 4 0
.so mmap 1162 144 48 0
.apk mmap 220 0 16 0
.ttf mmap 126 0 16 0
.dex mmap 2648 0 2644 0
code mmap 1220 0 88 0
image mmap 1051 508 8 0
Other mmap 23 4 0 0
Unknown 89 88 0 0
TOTAL 13323 7320 2824 0 18631 18036 13791
名词解释
- Native Heap: C++层内存分配。
- Dalvik Heap: Java层内存分配。
- Ashmem : 匿名共享内存。
- Stack: 栈区分配的内存。
- so mmap: C库代码占用。
- jar mmap : Java文件占用。
- apk mmap: apk代码占用。
- ttf mmap: ttf文件占用。
- dex mmap: dex文件代码占用的内存。
- Other mmap: 其他文件占用的内存
我们要关注 Dalvik Heap 和 Native Heap 占用内存,在使用应用过程中实时查看内存信息状态,来初步判断是否内存使用不当。
DDMS HEAP 工具
Android DDMS 内存监测工具 Heap,可以检测一个进程的内存变化,根据这个数值变化可以测试应用是否存在泄漏。
用过debug肯定会用 Heap 了,连接设备启动 app,点 debug 右边的按钮即可(Update Heap 鼠标放上去能看到)
DDMS 调试
开始GC,然后就操作 app 观察,Heap视图中部有一个data object,即数据对象,也就是我们的程序中对象
正常情况下 Total Size 值都会稳定在一个范围内,反之如果则 data object 的 Total Size 值在每次GC后不会有明显的回落
随着操作次数的增多 Total Size 的值会越来越大,就证明可能存在内存泄漏,然后通过其他工具来找出泄漏的地方;
MAT( Memory Analyzer Tool )
定位问题
通过 MAT 分析分析内存中占用比较大的对象
MAT 是一个内存分析工具,在使用 DEAP 初步判断页面存在内存泄露后,使用 MAT 具体分析出哪写对象没有释放,导致了内存没有释放,关于MAT工具安装,请自行 Google,操作 app,例如:进入某个页面,退出,点击 Dump Hprof file 按钮,等一会会打开MAT视图,没有安装会生成一个文件;
先观察“Leak suspects”,找出比较大的问题,通过 Dominator Tree 来查看 heap 中比较大的对象,也可以通过 Histogram 查找引用链;
Histogram 显示内存中每个对象的数量大小等信息,可以通过关键字来过滤
例如:搜索 com.main.*;这样就能查找出这些包下面类引用情况,自行右键获得信息,通过提示找出有问题的类或对象,这样就可以找出内存占用多或者泄露的问题了;
本例子中查看 Dominator Tree -> 右键某一条 -> Path to GC Roots -> exclude weak references
Shallow Heap:对象本身的大小
Retained Heap:对象本身以及它持有的对象的内存总和
验证
通过查看 Histogram 内存中的类以及实例个数
安装地址
总结
总结了一些常用的工具,用来分析内存问题,以下是注意的步骤
- 使用 ADB 命令初步分析内存
- 操作应用观察 HEAP update 查看当前内存变化,判断是否存在内存泄露
- 使用 MAT 来确定哪些代码引起了内存
如何避免
- 严格遵守生命周期,创建时创建,销毁时记得回收
- Bitmip 和 Drawable 记得手动回收
- 静态对象引用 Context,导致对象无法释放,从而导致 Activity 无法释放
- 自定义静态 Handler,Runnable 和 Handler 回收
- 使用 Application Context,少使用 Activity Context
- 手动解除监听绑定