Android内存检测工具系列工具

Android关于内存的工具不少,灵活地选择工具就显得特别重要。在此特别推荐分享涵盖一定初步和定位能力的工具,可以让我们一步到位地分析问题,提升效率。

在此列举几项:

工具 问题 能力
top/procrank 内存占用过大,内存泄露 发现
STRICTMODE activity泄露 发现
meminfo Native内存泄露、是否存在Activity、ApplicationContext泄露、数据库缓存命中率低 发现+初步定位
Finder/MAT/JHAT Java层的重复内存、不合理图片解码、内存泄露等 发现+定位
libc_malloc_deBug_leak.so Native内存泄露(JNI层) 发现+定位
LeakCannary/StrictMode activity泄露 自动发现+定位
APT 内存占用过大,内存泄露 发现
GC Log from Logcat、GC Log生成图标 人工触发GC for Explicit而导致的卡顿,Heap内存触发GC for Alloc而导致的卡顿 发现+初步定位
Systrace GC导致的卡顿 发现
Chrome devtool HS的内存问题 发现+定位
  1. meminfo

top/procrank得到的是内存曲线,但是输出列的信息中只包含RSS(Resident Set SIze
常驻集合大小)和VSS(Virtual Set Size 虚集合大小),有适用范围以及局限性较大。官方推荐的工具dumpsys
meminfo。

meminfo使用如下:

meminfo dump options:[-a][--oom][process]

其中,

  • -h 帮助信息。
  • -a 打印所有进程的内存信息,以及当前设备的内存概况。
  • –oom 按照OOM Adj值进行排序。 [process]可以是进程名称,也可以是进程ID,用于打印某个进程的内存信息。

另外配合命令行watch来观察meminfo也是不错的选择,例如每隔5,秒刷新一次:

watch -n 5 dumpsys meminfo com.wechat.qq。
  1. DDMS(Android Device Monitor)

DDMS全称:Dalvik Debug Monitor Service,即Dalvik虚拟机调试监控服务。DDMS是一个调试信息合集,里面包含时延、内存、线程、CPU、文件系统、流量等一系列信息的获取和展示,其中和内存相关主要有:Update Heap、Allocation Tracer,以及内存快照Dump Hprof file。

  • Update Heap:会获取GC的信息,包括当前已分配内存、当前存活的对象个数、所剩内存、动态虚拟机heapSize,还有一个分配大小的分布柱状图,主要用于查看,问题定位能力有限。
  • Allocation Tracker:会展示最近的500条内存分配,以及分配发生时刻的线程堆栈信息,官方推荐用它来提升流畅度。因为申请内存多,GC就多,而GC会挂起全部线程,引入卡顿问题。
  • Dump Hprof file:用于对选中的进程进行内存快照。
  • 现在使用的Android Studio里也有类似的工具,如Android Monitor。
  1. GC Log

跟GC相关的有两个工具,一个是在Logcat中输出的GC日志,另一个就是Allocation Tracer。而日志分成Dalvik的GC日志与ART的GC日志两种。

Dalvik GC产生的原因如下:

  • GC_EXPLICIT:通过Runtime.gc()与VMRuntime.gc(),SIGUSR1触发产生的GC,不支持局部GC但是支持并发GC,然而在列表滑动或动画播放时最好还是不要出现这类日志。因为在这种高CPU低响应时延的场景,人工触发GC来消耗CPU的行为应该尽可能避免。
  • GC_FOR_ALLOC:没有足够的内存空间给予即将分配的内存,这时会触发GC。这种不是并发GC,对卡顿的影响更大,应该尽量避免。QQ以内存触定率(MaxMemoryHeap的80%作为阀值)作为内存对用户的外网上报指标,其实就是根据GC for Alloc的概念提出的。
  • GC_FOR_CONCURRENT:当超出堆占用阀值时会自动触发。应该是最常见的GC了,也是最健康的GC.因为它支持局部GC、并发GC。所以暂停时间也是因为是并发GC,所以会分成mark和被修改对象的remark两部分耗时。
  • GC_BEFORE_OOM,在触发OOM之前触发的GC。这种GC不能并发不能局部GC,所以耗时长,也容易卡主界面。
  • GC_HPROF_DUMP_HEAP:在dump内存之前触发的GC。这种GC不能并发不能局部GC,所以耗时长,也容易卡主界面。

ART日志产生的常见原因:

  • Concurrent、Alloc、Explicit:跟Dalvik的基本上一致。
  • NativeAlloc:Native内存不足以分配内存时触发,跟Alloc类似。
  • Background:后台GC,触发是为了给后面的内存申请预留更多空间。

GC查询回收内存方式如下:

  • mark sweep:先记录全部对象,然后从GC ROOT开始找出间接和直接的对象并标注。利用之前记录的全部对象和标注对象对比,其余的对象就是需要回收的垃圾内存了。
  • concurrent mark sweep:使用mark sweep采集器的并发GC。
  • mark compact:在标记存活对象的时候,所有的存活对象压缩到内存的一端,而另一端可以更加高效的回收。
  • semispace:在做垃圾回收扫描的时候,把所以引用的对象从一个空间放到另一个空间,把剩余在旧的空间中的对象,直接GC整个空间即可。

通过GC日志,可以知道GC的量和它对卡顿的影响,也可以初步定位一些如主动调用GC、可分配的内存不足、过多使用Weak Reference等问题。

  1. Allocation Tracer
    在Android Studio里打开Android monitor,选择进程。点击Allocation Tracer,然后经过几秒或者同步观察GC日志发现问题的时候,再次点击Allocation Tracer暂停录制。这个时候观察代码区,会有录制结果。一般来说是层层展开的。通过dump to source跳转到对应的代码行分析即可。
  2. Android Profiler
    Android Profiler与Android monitor类似,可以分析执行进程的Memory、NetWork、CPU,在Android Studio里打开Android Profiler,选择指定进程,选择Memory选项,然后开始录屏,选取一段代码分析即可。