内存分析工具Memory Profiler和MAT

1.Memory Profiler

1.1Memory Profiler 的默认视图
image.png
  1. 用于强制执行垃圾回收事件的按钮。
  2. 用于捕获堆转储的按钮。
    注意:只有在连接到搭载 Android 7.1(API 级别 25)或更低版本的设备时,才会在堆转储按钮右侧显示用于记录内存分配]的按钮。
  3. 一个下拉菜单,用于指定分析器捕获内存分配的频率。选择适当的选项可帮助您在分析时提高应用性能。
  4. 用于放大/缩小时间轴的按钮。
  5. 用于跳转到实时内存数据的按钮。
  6. 事件时间轴,显示活动状态、用户输入事件和屏幕旋转事件。
  7. 内存使用量时间轴,它包括以下内容:
    • 一个堆叠图表,显示每个内存类别当前使用多少内存,如左侧的 y 轴以及顶部的彩色键所示。
    • 一条虚线,表示分配的对象数,如右侧的 y 轴所示。
    • 每个垃圾回收事件的图标。

不过,如果您使用的是搭载 Android 7.1 或更低版本的设备,则并非所有分析数据在默认情况下都可见。如果您看到一条消息,显示“Advanced profiling is unavailable for the selected process”,您需要启用高级分析才能看到以下内容:

  • 事件时间轴
  • 分配的对象数
  • 垃圾回收事件

要启用高级分析功能,请按以下步骤操作:

  • 依次选择 Run > Edit Configurations。
  • 在左侧窗格中选择您的应用模块。
  • 点击 Profiling 标签,然后勾选 Enable advanced profiling。重新编译并运行您的应用。
  • 在 Android 8.0 及更高版本上,始终为可调试应用启用高级分析。
1.2内存分析
image.png

内存计数中的类别如下:

  • Java:从 Java 或 Kotlin 代码分配的对象的内存。
  • Native:从 C 或 C++ 代码分配的对象的内存。
    即使您的应用中不使用 C++,您也可能会看到此处使用的一些原生内存,因为 Android 框架使用原生内存代表您处理各种任务,如处理图像资源和其他图形时,即使您编写的代码采用 Java 或 Kotlin 语言。
  • Graphics:图形缓冲区队列向屏幕显示像素(包括 GL 表面、GL 纹理等等)所使用的内存。(请注意,这是与 CPU 共享的内存,不是 GPU 专用内存。)
  • Stack:您的应用中的原生堆栈和 Java 堆栈使用的内存。这通常与您的应用运行多少线程有关。
  • Code:您的应用用于处理代码和资源(如 dex 字节码、经过优化或编译的 dex 代码、.so 库和字体)的内存。
  • Others:您的应用使用的系统不确定如何分类的内存。
  • Allocated:您的应用分配的 Java/Kotlin 对象数。此数字没有计入 C 或 C++ 中分配的对象。
    如果连接到搭载 Android 7.1 及更低版本的设备,只有在 Memory Profiler 连接到您运行的应用时,才开始此分配计数。因此,您开始分析之前分配的任何对象都不会被计入。不过,Android 8.0 及更高版本附带一个设备内置分析工具,该工具可跟踪所有分配,因此,在 Android 8.0 及更高版本上,此数字始终表示您的应用中待处理的 Java 对象总数。
1.3内存收集结果
image.png
  • Allocations:堆中的分配数。

  • Native Size:此对象类型使用的原生内存总量(以字节为单位)。只有在使用 Android 7.0 及更高版本时,才会看到此列。

    您会在此处看到采用 Java 分配的某些对象的内存,因为 Android 对某些框架类(如 Bitmap)使用原生内存。

  • Shallow Size:此对象类型使用的 Java 内存总量(以字节为单位)。

  • Retained Size:为此类的所有实例而保留的内存总大小(以字节为单位)。

您可以使用已分配对象列表上方的两个菜单来选择要检查的堆转储以及如何组织数据。

从左侧的菜单中,选择要检查的堆:

  • default heap:当系统未指定堆时。
  • app heap:您的应用在其中分配内存的主堆。
  • image heap:系统启动映像,包含启动期间预加载的类。此处的分配保证绝不会移动或消失。
  • zygote heap:写时复制堆,其中的应用进程是从 Android 系统中派生的。

从右侧的菜单中,选择如何安排分配:

  • Arrange by class:根据类名称对所有分配进行分组。这是默认选项。
  • Arrange by package:根据软件包名称对所有分配进行分组。
  • Arrange by callstack:将所有分配分组到其对应的调用堆栈。只有在记录分配期间捕获堆转储时,此选项才有效。即便如此,堆中也很可能有在您开始记录之前分配的对象,所以会先显示这些分配,直接按类名称列出它们。

默认情况下,此列表按 Retained Size 列排序。要按其他列中的值排序,请点击该列的标题。

点击一个类名称可在右侧打开 Instance View 窗口。列出的每个实例都包含以下信息:

  • Depth:从任意 GC 根到选定实例的最短跳数。
  • Native Size:原生内存中此实例的大小。只有在使用 Android 7.0 及更高版本时,才会看到此列。
  • Shallow Size:Java 内存中此实例的大小。
  • Retained Size:此实例支配的内存大小。

分析简单的内存泄露的时候,可以通过Activity来回旋转或者Activity进入退出来查看对应Activity的实例个数。
分析内存溢出的时候,可以依据Shallow Size等参数作为参考,查看实例的个数与大小,从而定位到内存溢出的具体的问题。

1.4将堆转储另存为 HPROF 文件

您可以使用 android_sdk/platform-tools/ 目录中提供的 hprof-conv工具执行此操作。运行包含两个参数(即原始 HPROF 文件和转换后 HPROF 文件的写入位置)的 hprof-conv 命令。例如:

hprof-conv heap-original.hprof heap-converted.hprof

hprof文件转换成功后就可以使用其他的内存分析工具来分析了,比如MAT等。

2.MAT

MAT是Memory Analyzer的简称,它是一款功能强大的Java堆内存分析器。可以用于查找内存泄露以及查看内存消耗情况。MAT是基于Eclipse开发的,是一款免费的性能分析工具。读者可以在http://www.eclipse.org/mat/下载并使用MAT。
使用步骤:

  • 1.首先通过Memory Profiler抓取hprof
  • 2.使用命令转成MAT工具识别的文件
hprof-conv heap-original.hprof heap-converted.hprof
  • 3.使用Eclipse打开hprof文件
  • 4.工具加载成功后,会生成内存泄漏的可疑报告。然后点击Open Dominator Tree for entire Heaps,查询Heap的树形结构。
    image.png
  • 5.通过open query browser也就是图片的第二个红框进行条件查询。一般情况下是通过Path to Gc Root,去除所有软弱等引用,得到剩余的一些对象,这些对象基本上就是发生泄漏问题的对象。
    或者可以直接搜索可疑的对象类名称,查询对应的引用。
    image.png

    如上图,我们看下MainActivity2对象有好几个,同时处于no GC root状态,这时候我们就可以知道MainActivity2对象发生了泄漏,此时右击该对象,选择Merge ShorTest Path to Gc Roots,得到该对象具体的引用路径。
    image.png

    此时我们就定位到了MainActivity2类的mContext属性发生了泄漏。因此我们就可以针对此进行代码层面的优化。

以上是这两个内存分析工具的简单使用,这些工具还有很多其他的功能,比如线程监控等,有兴趣的同学可以深入研究。

你可能感兴趣的:(内存分析工具Memory Profiler和MAT)