相关文章
Android性能优化系列
Java虚拟机系列html
在这个系列的前四篇文章中,我分别介绍了DVM、ART、内存泄漏和内存检测工具的相关知识点,这一篇咱们经过一个小例子,来学习如何使用内存分析工具MAT。
java
在进行内存分析时,咱们可使用Memory Monitor和Heap Dump来观察内存的使用状况、使用Allocation Tracker来跟踪内存分配的状况,也能够经过这些工具来找到疑似发生内存泄漏的位置。可是若是想要深刻的进行分析并肯定内存泄漏,就要分析
疑似发生内存泄漏时所生成堆存储文件。堆存储文件可使用DDMS或者Memory Monitor来生成,输出的文件格式为hpof,而MAT就是来分析堆存储文件的。
MAT,全称为Memory Analysis Tool,是对内存进行详细分析的工具,它是Eclipse的插件,若是用Android Studio进行开发则须要单独下载它,下载地址为:eclipse.org/mat/,这篇文章MA…android
咱们须要准备一段发生内存泄漏代码,以下所示。正则表达式
public class MainActivity extends AppCompatActivity {
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
LeakThread leakThread = new LeakThread();
leakThread.start();
}
class LeakThread extends Thread {
@Override
public void run() {
try {
Thread.sleep(60 * 60 * 1000);
} catch (InterruptedException e) {
e.printStackTrace();
}
}
}
}复制代码
上面的代码是很典型的内存泄漏的例子,缘由就是非静态内部类LeakThread持有外部类MainActivity的引用,LeakThread中作了耗时操做,致使MainActivity没法被释放,关于内存泄漏能够查看Android内存优化(三)避免可控的内存泄漏这篇文章。express
生成hpof文件主要分为如下几个步骤:数组
DDMS生成的hprof文件并非标准的,还须要将它转换为标准的hprof文件,这样才会被MAT识别从而进行分析,可使用SDK自带的hprof-conv进行转换,它的路径在sdk/platform-tools中,进入到该路径执行如下语句便可:性能优化
hprof-conv D:\before.hprof D:\after.hprof复制代码
其中 D:\before.hprof 是要转换的hprof文件路径,D:\after.hprof 则是转换后hprof文件的保存路径。bash
除了用DDMS来生成hpof文件,还能够用AS的Memory Monitor来生成hpof文件。
生成hpof文件主要分为一下几个步骤:微信
Memory Monitor生成的hpof文件也不是标准的,AS提供了便捷的转换方式:Memory Monitor生成的hpof文件都会显示在AS左侧的Captures标签中,在Captures标签中选择要转换的hpof文件,并点击鼠标右键,在弹出的菜单中选择Export to standard.hprof选项,便可导出标准的hpof文件,以下图所示。
app
用MAT打开标准的hpof文件,选择Leak Suspects Report选项。这时MAT就会生成报告,这个报告分为两个标签页,一个是Overview,一个是Leak Suspects(内存泄漏猜测),以下图所示。
打开Overview标签页,首先看到的是一个饼状图,它主要用来显示内存的消耗,饼状图的彩色区域表明被分配的内存,灰色区域的则是空闲内存,点击每一个彩色区域能够看到这块区域的详细信息,以下图所示。
再往下看,Actions一栏的下面列出了MAT提供的四种Action,其中分析内存泄漏最经常使用的就是Histogram和Dominator Tree。咱们点击Actions中给出的连接或者在MAT工具栏中就能够打开Dorminator Tree和Histogram,以下图所示。
其中左边第二个选项是Histogram,第三个选项是Dorminator Tree,第四个是OQL,下面分别对它们进行介绍。
Dorminator Tree意味支配树,从名称就能够看出Dorminator Tree更善于去分析对象的引用关系。
图中能够看出Dorminator Tree有三列数据。
Retained Set指的是这个对象自己和他持有引用的对象以及这些引用对象的Retained Set所占内存大小的总和,官方的图解以下所示。
从图中能够看出E的Retained Set为E和G。C的Retained Set为C、D、E、F、G、H。
MAT所定义的支配树就是从上图的引用树演化而来。在引用树当中,一条到Y的路径必然会通过X,这就是X支配Y。X直接支配Y则指的是在全部支配Y的对象中,X是Y最近的一个对象。支配树就是反映的这种直接支配关系,在支配树中,父节点直接支配子节点。下图就是官方提供的一个从引用树到支配树的转换示意图。
C直接支配D、E,所以C是D、E的父节点,这一点根据上面的阐述很容易得出结论。C直接支配H,这可能会有些疑问,能到达H的主要有两条路径,而这两条路径FD和GE都不是必需要通过的节点,只有C知足了这一点,所以C直接支配H,C就是H的父节点。经过支配树,咱们就能够很容易的分析一个对象的Retained Set,好比E被回收,则会释放E、G的内存,而不会释放H的内存,由于F可能还引用着H,只有C被回收,H的内存才会被释放。
这里对支配树进行了讲解,咱们能够得出一个结论:经过MAT提供的Dominator Tree,能够很清晰的获得一个对象的直接支配对象,若是直接支配对象中出现了不应有的对象,就说明发生了内存泄漏。
在Dominator Tree的顶部Regex能够输入过滤条件(支持正则表达式),若是是查找Activity内存泄漏,能够在Regex中输入Activity的名称,好比咱们这个例子能够输入MainActivity,效果以下图所示。
Merge Shortest Paths to GC Root选项主要用来显示距离GC Root最短的路径,根据引用类型会有多种选项,好比with all references就是包含全部的引用,这里咱们选择exclude all phantom/weak/soft etc. references,由于这个选项排除了虚引用、弱引用和软引用,这些引用通常是能够被回收的。这时MAT就会给出MainActivity的GC引用链。
Histogram与Dominator Tree不一样的是,Dominator Tree是在对象实例的角度上进行分析,注重引用关系分析,而Histogram则在类的角度上进行分析,注重量的分析。
Histogram中的内容以下图所示。
能够看到Histogram中共用四列数据,关于Shallow Heap和Shallow Heap的含义咱们在3.1节已经知道了,剩余的 Class Name表明类名,Objects表明对象实例的个数。
在Histogram的顶部Regex一样能够输入过滤条件,这里一样输入MainActivity,效果以下图所示。
MainActivity和LeakThread实例各为11个,基本上能够判定发生了内存泄漏。具体内存泄漏的缘由,一样能够查看GC引用链。在MainActivity一项单击鼠标右键,选择Merge Shortest Paths to GC Root,并在选项中选择exclude all phantom/weak/soft etc. references以下图所示。
OQL全称为Object Query Language,相似于SQL语句的查询语言,可以用来查询当前内存中知足指定条件的全部的对象。它的查询语句的基本格式为:
SELECT * FROM [ INSTANCEOF ] <class_name> [ WHERE <filter-expression>]复制代码
当咱们输入select * from instanceof android.app.Activity并按下F5时(或者按下工具栏的红色叹号),会将当前内存中全部Activity都显示出来,以下图所示。
select * from com.example.liuwangshu.leak.MainActivity复制代码
经过查看GC引用链也能够找到内存泄漏的缘由。关于OQL语句有不少用法,具体能够查看官方文档。
由于咱们这个例子很简单,能够经过上面的方法来找到内存泄漏的缘由,可是复杂的状况就须要经过对比hpof文件来进行分析了。使用步骤为:
在Compared Tables也有顶部Regex,输入MainActivity进行筛选。
能够看到MainActivity在这一过程当中增长了6个,MainActivity的实例不该该增长的,这说明发生了内存泄漏,能够经过查看GC引用链来找到内存泄漏的具体的缘由。
除了上面的对比方法,Histogram还能够经过工具栏的对比按钮来进行对比:
生成的结果和Compared Tables相似,咱们输入MainActivity进行筛选:
能够看到第二个hpof文件比第一个hpof文件多了6个MainActivity实例。
MAT还有不少功能,这里也只介绍了经常使用的功能,其余的功能就须要读者在使用过程当中去发现并积累。
参考资料
《Android群英传 神兵利器》
《Android应用性能优化最佳实践》
《高性能Android应用开发》
利用MAT进行内存泄露分析
Android最佳性能实践(二)——分析内存的使用状况
Memory Analyzer
欢迎关注个人微信公众号,第一时间得到博客更新提醒,以及更多成体系的Android相关原创技术干货。
扫一扫下方二维码或者长按识别二维码,便可关注。