💎一站式轻松地调用各大LLM模型接口,支持GPT4、智谱、星火、月之暗面及文生图 广告
### 15.2 内存泄露分析之MAT工具 MAT的全称是Eclipse Memory Analyzer,它是一款强大的内存泄露分析工具,MAT不需要安装,下载后解压即可使用,下载地址为http://www.eclipse.org/mat/downloads.php。对于Eclipse来说,MAT也有插件版,但是不建议使用插件版,因为独立版使用起来更加方便,即使不安装Eclipse也可以正常使用,当然前提是有内存分析后的hprof文件。 为了采用MAT来分析内存泄露,下面模拟一种简单的内存泄露情况,下面的代码肯定会造成内存泄露: public class MainActivity extends Activity { private static final String TAG = "MainActivity"; private static Context sContext; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); sContext = this; } } 编译安装,然后打开DDMS界面,其中AndroidStudio的DDMS位于Monitor中。接着用鼠标选中要分析的进程,然后使用待分析应用的一些功能,这样做是为了将尽量多的内存泄露暴露出来,然后单击Dump HPROF file这个按钮(对应图15-1中底部有黑线的按钮),等待一小段时间即可导出一个hprof后缀的文件,如图15-1所示。 :-: ![](https://img.kancloud.cn/2e/d5/2ed533218cae855b910a07bcbe3a736b_1361x528.png) 图15-1 DDMS视图 导出hprof文件后并不能使用它来进行分析,因为它不能被MAT直接识别,需要通过hprof-conv命令转换一下。hprof-conv命令是Android SDK提供的工具,它位于Android SDK的platform-tools目录下: hprof-conv com.ryg.chapter_15.hprof com.ryg.chapter_15-conv.hprof 当然如果使用的是Eclipse插件版的MAT的话,就可以不进行格式转换了,可以直接用MAT插件打开。 经过了上面的步骤,接下来就可以直接通过MAT来进行内存分析了。打开MAT,通过菜单打开刚才转换后的com.ryg.chapter_15-conv.hprof这个文件,打开后的界面如图15-2所示。 :-: ![](https://img.kancloud.cn/3d/a3/3da31abd2c291b059203c376790abdcb_967x611.png) 图15-2 MAT的内存分析主界面 如图15-2所示,MAT提供了很多功能,但是最常用的只有Histogram和Dominator Tree,通过Histogram可以直观地看出内存中不同类型的buffer的数量和占用的内存大小,而Dominator Tree则把内存中的对象按照从大到小的顺序进行排序,并且可以分析对象之间的引用关系,内存泄露分析就是通过Dominator Tree来完成的。图15-3和图15-4分别是MAT中Histogram和Dominator Tree的界面。 :-: ![](https://img.kancloud.cn/ed/24/ed24b6b23e0f5ced8ce4cf9daa77568e_970x607.png) 图15-3 MAT中Histogram的界面 :-: ![](https://img.kancloud.cn/e5/b9/e5b964fc23ba0fff0be423d6502951eb_965x606.png) 图15-4 MAT中Ddominator Tree的界面 为了分析内存泄露,我们需要分析Dominator Tree里面的内存信息,在Dominator Tree中内存泄露的原因一般不会直接显示出来,这个时候需要按照从大到小的顺序去排查一遍。一般来说Bitmap泄露往往都是由于程序的某个地方发生了内存泄露都引起的,在图15-4中的第2个结果就是一个Bitmap泄露,选中它然后单击鼠标右键->Path To GC Roots->exclude wake/soft references,如图15-5所示。可以看到sContext引用了Bitmap最终导致了Bitmap无法释放,但其实根本原因是sContext无法释放所导致的,这样我们就找出了内存泄露的地方。Path To GC Roots过程中之所以选择排除弱引用和软引用,是因为二者都有较大几率被gc回收掉,它们并不能造成内存泄露。 :-: ![](https://img.kancloud.cn/e0/07/e007163175263f90b66318f210ccaf2f_1338x600.png) 图15-5 Path To GC Roots后的结果 在Dominator Tree界面中是可以使用搜索功能的,比如我们尝试搜索MainActivity,因为这里我们已经知道MainActivity存在内存泄露了,搜索后的结果如图15-6所示。我们发现里面有6个MainActivity的对象,这是因为每次按back键退出再重新进入MainActivity,系统都会重新创建一个新的MainActivity,但是由于老的MainActivity无法被回收,所以就出现了多个MainActivity对象的情形。另外MAT还有很多其他功能,这里就不再一一介绍了,请读者自己体验吧。 :-: ![](https://img.kancloud.cn/a9/64/a964f9c1bcb4026f174f7a23afde7071_1110x610.png) 图15-6 Dominator Tree的搜索功能