Android 内存优化(1) - MAT 使用入门

367 阅读2分钟
一、内存分析三步走:从现象到本质

当应用出现卡顿、OOM崩溃或内存曲线呈“阶梯式增长”时,就该请出内存分析神器——MAT(Memory Analyzer Tool)。整个分析流程可拆解为:

1. 捕获内存快照
通过adb shell am dumpheap <PID> /sdcard/heapdump.hprof命令生成堆转储文件,或使用Android Studio的Memory Profiler直接导出。

2. MAT工具初探
将.hprof文件拖入MAT,首先会看到概览面板:

  • Actions:推荐先执行Histogram(直方图)或Dominator Tree(支配树)分析
  • OQL查询:支持类似SQL的语法,如SELECT * FROM instanceof android.app.Activity

3. 关键指标解读

  • Shallow Heap:对象自身占用的内存(不包含引用对象)
  • Retained Heap:对象被回收后能释放的总内存(含其直接或间接引用的对象)
  • GC Roots:从根节点(如静态变量、线程、JNI引用)出发的引用链
二、Dominator Tree:定位内存泄漏的“藏宝图”

1. 核心操作

  • 在MAT中打开Dominator Tree视图
  • Retained Heap降序排列
  • 重点关注前几名的大对象(尤其是自定义类)

2. 典型泄漏模式

  • 单例持有Activity

    	MySingleton -> mContext -> MyActivity
    

    修复方案:单例中避免持有Activity,改用Application Context。

  • 匿名内部类陷阱

    	MainActivity$1 (Handler) -> MainActivity
    

    修复方案:使用静态内部类+WeakReference组合。

  • 未注销的监听器

    	SensorManager -> Listener -> MyActivity
    

    修复方案:在onPause中调用unregisterListener

三、OQL查询:内存问题的“CT扫描”

1. 常用查询模板

  • 查找所有Activity实例:

    sql
    	SELECT * FROM INSTANCEOF android.app.Activity
    
  • 统计Bitmap数量:

    sql
    	SELECT COUNT(*) FROM INSTANCEOF android.graphics.Bitmap
    
  • 查找未关闭的Cursor:

    sql
    	SELECT * FROM android.database.Cursor WHERE isClosed() = false
    

2. 实战案例
某应用出现内存泄漏,通过OQL查询:

sql
	SELECT s.toString(), COUNT(*) FROM INSTANCEOF java.lang.String s GROUP BY s ORDER BY COUNT(*) DESC

发现大量重复的"com.example.MyFragment"字符串,最终定位到Fragment未正确销毁。

四、线程分析:揪出内存抖动的“幕后黑手”

1. 线程视图入口
在MAT中打开Thread Overview,重点关注:

  • 线程数量是否异常(正常应用线程数应<50)
  • 是否存在大量Runnable线程

2. 典型问题场景

  • 线程池泄漏

    	ThreadPoolExecutor -> Worker -> Runnable -> MyTask -> MyActivity
    

    修复方案:使用Executors.newSingleThreadExecutor()替代手动管理线程。

  • AsyncTask未取消

    	AsyncTask$1 -> MyActivity
    

    修复方案:在onDestroy中调用cancel(true)

五、进阶技巧:对比分析+路径追踪

1. 内存快照对比

  • 生成操作前后的两个.hprof文件
  • 在MAT中打开Compare Basket视图
  • 重点关注Diff列变化,定位内存增长点

2. 路径追踪

  • 右键点击可疑对象,选择Path To GC Roots

  • 排除Weak/Soft/Phantom引用,定位强引用链

  • 示例路径:

    	MyActivity -> View -> Handler -> MessageQueue -> Looper -> Thread
    
六、总结:MAT工具的“降维打击”

MAT工具就像内存分析的“显微镜”,通过:

  • Dominator Tree定位内存大户
  • OQL查询精准扫描问题对象
  • 线程分析揪出资源泄漏
  • 对比分析量化内存变化

掌握这些技巧后,即使是复杂的内存泄漏问题也能迎刃而解。记住:内存优化没有银弹,但MAT绝对是你最趁手的“内存猎刀”

参考文档

  1. Shallow and retained sizes
  2. MAT的wiki:wiki.eclipse.org/index.php/M…
  3. Android 内存优化(1) - MAT 使用入门 · Android Performance