专注于 JetBrains IDEA 全家桶,永久激活,教程
持续更新 PyCharm,IDEA,WebStorm,PhpStorm,DataGrip,RubyMine,CLion,AppCode 永久激活教程

探索App性能优化之内存优化-内存分析工具MAT

一、MAT概述

在进行内存分析时,可以使用Android Studio自带的Memory Profiler和Heap Dump(堆转储)来观察内存的使用情况、使用Allocation Tracker(分配跟踪器)来跟踪内存分配的情况,也可以通过这些工具来找到疑似发生内存泄漏的位置。

如果想要深入的进行分析并确定内存泄漏,就要分析疑似发生内存泄漏时所生成hprof(堆存储文件)。堆存储文件可以使用DDMS或者Memory Profiler来生成,输出的文件格式为hpof,而MAT就是来分析堆存储文件的。 MAT,全称为Memory Analysis Tool,是对内存进行详细分析的工具,它是Eclipse的插件,如果用Android Studio进行开发则需要单独下载MAT

二、生成hprof文件

1、准备内存泄漏代码

我们需要准备一段发生内存泄漏代码,如下所示:

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无法被释放。将MainActivity的实例被一个非静态内部类LeakThread对象所持有,在旋转屏幕的时候造成内存泄漏,简单的先旋转屏幕10次吧。

2、使用Android Profiler生成hprof文件

58_1.png

  • 第一步:启动Android Profiler
  • 第二步:点击MEMORY进入memory详情
  • 第三步:制造泄露
  • 第四步:点击 Dump Java Heap 生成内存堆栈详情Heap Dump
  • 第五步:点击Export heap dump to hprof file,生成.hprof文件

现在已经保存了一份发生内存泄露的.hprof文件,命名为1.hprof,然后将APP完全退出重新启动 打开Android Profiler点击Dump java Heap生成一份没发生内存泄漏(没旋转屏幕)的内存快照hprof文件,保存命名为2.hprof

现在就已经生成好了两份hprof文件,一份是发生内存泄漏的1.hprof和,一份没有内存泄漏的2.hprof。

3、将Android Studio导出的hprof文件转换成MAT支持的hprof文件

MAT不支持Android Studio生成的未经转换的,直接用MAT打开报错如下:

58_2.png原因:

Android的虚拟机导出的内存文件hprof文件格式与标准的 java hprof文件格式标准不一样,根本原因两者的虚拟机不一致导致的。

解决方法:

只需要使用SDK中自带的转换工具转换就可以了,需要我们手动的通过sdk的platform-tools包下的hprof-conv.exe来转换成标准的hprof文件。

(1)首先打开cmd命令行进入hprof-conv.exe所在的文件夹

(2)然后执行如下命令: hprof-conv 1.hprof 111.hprof,其中1.hprof为原始文件,111.hprof为转换过后的文件。

1、hprof和111.hprof文件,都要加上文件路径(如果不加上路径,就把这个文件放到和hprof-conv.exe同级目录下),转换后的111.hprof文件就可以用MAT打开了。

三、MAT分析hprof文件

用MAT打开标准的hpof文件,Open File–>选择文件–>Leak Suspects Report–>Finish。这时MAT就会生成报告,这个报告分为两个标签页,一个是Overview,一个是Leak Suspects(内存泄漏猜想),如下图所示:

1、Leak Suspects(内存泄漏猜想)

58_3.pngLeak Suspects中会给出了MAT认为可能出现内存泄漏问题的地方,上图共给出了2个内存泄漏猜想,通过点击每个内存泄漏猜想的Details可以看到更深入的分析清理情况。如果内存泄漏不是特别的明显,通过Leak Suspects是很难发现内存泄漏的位置。个人认为,Leak Suspects猜想不算好用,不再研究了。

2、Overview视图

打开Overview标签页,首先看到的是一个饼状图,它主要用来显示内存的消耗,其中涉及的类有多少,对象有多少,类加载器,如果有没有回收的对象,会有一个连接,可以直接参看(图中的Unreachable Objects Histogram)。饼状图的彩色区域代表被分配的内存,灰色区域的则是空闲内存,点击每个彩色区域可以看到这块区域的详细信息,如下图所示:

58_4.png

Actions一栏的下面列出了MAT提供的四种Action:

Histogram视图: 列举内存中对象存在的个数和大小 Dominator Tree视图:该视图会以占用总内存的百分比来列举所有实例对象,注意这个地方是对象而不是类了,这个视图是用来发现大内存对象的 Top Consumers: 该视图会显示可能的内存泄漏点 Duplicate Classes: 该视图显示重复的类等信息

其中分析内存泄漏最常用的就是Histogram和Dominator Tree。Histogram视图是最重要的,其他三个视图也只是提供一些可能会造成内存泄漏的信息,点击Actions中给出的链接或者在MAT工具栏中就可以打开Dorminator Tree和Histogram,如下图所示:

58_5.png

四、分析Histogram视图

1、点击Actions中给出的Histogram视图链接,打开Histogram视图。

2、打开下面的面板Navigation History 选中histogram右键Add to Compare Basket添加到比较容器中,两个个hprof文件(111.hprof和222.hprof)都做以上同样的操作 将histogram 添加到比较容器中。

58_6.png

3、这时比较容器中就有两份份hprof文件,111.hprof和222.hprof(注意:导入的比较容器的顺序很重要,不然后面的数据看起来让人费解),然后点击Compare the results (红色感叹号)进行比较

58_7.png

4、通过比较后就会生成一个比较结果表ComPared Tables

58_8.png

5、但是这个表内容太多,我们需要快速过滤出与我们的项目有关的内容, 接着在Class Name 输入我们的项目包名

58_9.png

6、通上图就明显看出经过两个hprof比较,在我们操作了旋转多次屏幕后MainActivity的实例增加了,然后我们就去分析下111.hprof文件是导致MainActivity内存泄漏的原因

58_10.png

7、在Class Name处可以根据输入的类名去查找对应的对象实例(比如输入MainActivty)

58_11.pngObjects:实例个数

Shallow Heap:所占内存大小

Retained Heap:释放后能回收多少内存

8、通过上图看到了MainActivtiy在旋转屏幕后产生了10个实例,再去查看MainActivtiy具体被哪些对象引用了,右键MainActivtiy实例选择by incoming references

58_12.png

58_13.png

58_14.png

9、看到MainActivty被引用的地方这么多,而且一屏还显示不完,我们又如何去判断是哪个导致内存泄漏的呢?MAT还有一个功能就是通过遍历GC Root树去把那些有可能被GC回收的实例去将他们去除(在GC Root树中能找到的对象绝对不存在有内存泄漏的实例,因为他们在运行时会被回收了,只有找不到的那些才是有可能发生内存泄漏的实例)

58_15.png

10、最后我们就看到了LeakThread引用了MainActivty实例

58_16.png

五、总结

通过一个简单的案例学会使用MAT去查找项目中泄漏的地方,在真实的项目开发过程中就不止有LeakThread一个类,还有许多其他的类,也不可能是只有一种原因:非静态内部类持有外部类的引用,会有许多原因,需要一一去逐步分析是否有内存泄漏的可能。(体力活)

比如页面A跳转到页面B 在返回页面A内存却居高不下,然后就在跳转之前生成一份hprof文件跳转之后再生成一份hprof文件 通过MAT一比较检索出与页面A和B有关的内存情况,精确定位内存泄漏的地方,将范围缩小,省时省力。

文章永久链接:https://tech.souyunku.com/27625

未经允许不得转载:搜云库技术团队 » 探索App性能优化之内存优化-内存分析工具MAT

JetBrains 全家桶,激活、破解、教程

提供 JetBrains 全家桶激活码、注册码、破解补丁下载及详细激活教程,支持 IntelliJ IDEA、PyCharm、WebStorm 等工具的永久激活。无论是破解教程,还是最新激活码,均可免费获得,帮助开发者解决常见激活问题,确保轻松破解并快速使用 JetBrains 软件。获取免费的破解补丁和激活码,快速解决激活难题,全面覆盖 2024/2025 版本!

联系我们联系我们