android 如何分析应用的内存(十七)——使用MAT查看Android堆

android 如何分析应用的内存(十七)——使用MAT查看Android堆

前一篇文章,介绍了使用Android profiler中的memory profiler来查看Android的堆情况。
如Android 堆中有哪些对象,这些对象的引用情况是什么样子的。

可是我们依然面临一个比较严峻的挑战:不管是app开发者,还是内存分析者而言,堆中的对象,非常之多,不仅有Android 原生的类,还有第三方库使用的类。这些类在使用过程中,也可能因为有较大的shallow size 或者retained size而混淆内存的分析。

为了解决这样的问题,我们更希望,通过不同时间点的堆,进行差分比较。即在时刻t1生成的堆heap1和t2时刻生成的堆heap2进行相互比较。

为此,我们将介绍java开发中重要的内存分析工具MAT。

MAT使用前的准备

在上一篇文章中,我们使用AS捕获了堆,现在我们需要将其导出,用在MAT工具上。如下图:
在这里插入图片描述

接下来将Android保存的heap dump进行格式转换,以满足MAT的需求。转换格式的工具在Android SDK中。如下:

/Users/biaowan/Library/Android/sdk/platform-tools/hprof-conv ./mat/memory-test_malloc_int\[\].hprof mat_test1.hprof

在这里插入图片描述

MAT的使用

打开MAT之后,进入菜单栏->File->Open File。然后选择刚才转换之后的mat_test.hprof文件。如下图
在这里插入图片描述

可见,主界面显示一个overview的界面,该界面用英文详细表述了具体细节,不在赘述。下面解释上图的八个标记。

  • 标记1:打开overview 界面。即上面的主界面。

  • 标记2:打开当前堆中的对象分布情况,默认按照类名进行排序。右键可以进行相应操作,各个操作什么意思,已经标明。如下图
    在这里插入图片描述

  • 标记3:显示本heap中的所有dominator tree(注意:dominator tree,已经在上一篇文章中介绍:android 如何分析应用的内存(十六)——使用AS查看Android堆:http://t.csdn.cn/GTWpR). 而各个对象应该怎么查看其对应的dominator tree。见标记2对应的右键说明。

  • 标记4:Open Object Qurey Language,类似于使用SQL语句进行查询。因为MAT提供的菜单功能已经完全够Android使用,因此本文不再介绍

  • 标记5:展示线程的名字,堆栈,本地变量等。但是Android 没有提供这个功能,因此无法使用

  • 标记6:打印各种报告,如下图标记
    在这里插入图片描述

  • 标记7:即为标记2中,右键支持的各种操作,详见标记2

  • 标记8:搜索按钮,可以按照地址进行搜索

为了能够详细说明,如何操作MAT,下文将会以各种问题作为模板,详细介绍操作过程

问题1:如何查看某个类有哪些对象

  1. 点击标记1,打开所有类的列表。
  2. 在第一行,键入需要查找的类,或者按照不同的大小进行排序和过滤
  3. 选中类,然后点击右键,选择List Objects.然后按照需求列出各个对象
    在这里插入图片描述

问题2:如何查看某个对象到GC root的引用链

  1. 选中某个对象,右键选中Paths to GC root
  2. 再次选中exclude all xxx references
    在这里插入图片描述

可见整个引用链清晰明了,不在绘图说明

问题3:如何查看对象的Dominator tree(支配树)

  1. 选中对象,右键选择Java Basics
  2. 再次选中Open in Dominator tree
  3. 在弹出的框中,选择finish。默认以对象排序
    在这里插入图片描述

从图中可以看到TaskRunable对象直接支配两个对象,一个int数组,一个弱引用

问题4:如何查看一个对象的直接支配者

  1. 选中对象,然后右键,选择immediate dominator
  2. 在弹出框中,选择finish
    在这里插入图片描述

可以看到我们选中的TaskRunable对象的直接支配者是一个Task对象

问题5:如何查看类加载器,是否重复加载同一个类

  1. 点击标记1,打开overview界面
  2. 滚动界面到最底下
  3. 选择Duplicate classes
    在这里插入图片描述

问题6:如何查看堆中,最占内存的部分

  1. 点击标记1,打开overview界面
  2. 滚动至最底下
  3. 选择Top cosumer
    在这里插入图片描述

从图中可以看到,分别按照对象,类,类加载器,包名列出了最占内存的部分

问题7:如何查看堆的报告

  1. 点击标记6.选择Heap dump overview
  2. 在对报告中,点击table of content 查看内容表(该字段,在报告的底部)
    在这里插入图片描述

从中也可以直接查看最占内存的对象

问题8:如何进行泄露检查

  1. 点击标记6,选择Leak Suspect
    在这里插入图片描述

从图中可以看到,有三个怀疑的对象,往下滚动,可以看到三个怀疑对象的详细细节,如下
在这里插入图片描述

图中,简要说明了Task类,有2100个实例,占了29.51%的内容。点击details它会显示相应的引用链路径。可清晰看到GC root的整个引用链。

多个Heap进行差分分析,查找内存问题

为了一步步演练,如何使用多个heap进行差分分析,我们选择上一篇文章方案2中的例子:android 如何分析应用的内存(十六)——使用AS查看Android堆:http://t.csdn.cn/JYGFC。然后在同一个进程的两个不同时刻,分别选取不同的heap,分别叫as_heap1.hprof和as_heap2.hprof.

场景1:MAT 自动分析两个堆之间的内存泄露

  1. 按照上文提及的hprof-conv工具,将as_heap1.hprof,as_heap2.hprof分别转换为mat_heap1.hprof,mat_heap2.hprof。然后用mat工具将其打开。

  2. 打开第二个heap的overvie操作栏,即标记1。滚动到最底部

  3. 选择Leak suspects by Snapshot comparision.

  4. 在弹出的框中,选择mat_heap1.hprof。然后点击finish。让mat_heap2.hprof与mat_heap1.hprof做差分分析,然后给出一个报告,如下(需要等待一段时间)
    在这里插入图片描述
    在这里插入图片描述

从图中可以看到,怀疑com.example.test_malloc.Task对象泄露,它有4900个对象,占整个堆的49.26%。点击details可以看到这个引用链,如下图
在这里插入图片描述

从图中可以看到,Task被DeviceManager的listener所持有,导致GC无法回收。所以找到了内存泄露点。

场景2:无法自动分析时,手动分析

当两个heap堆,间隔时间较短,泄露的对象,占据整个堆的空间较小,此时mat无法进行自动分析。此时我们可以手动分析。

接下来,我们用时间间隔较小的两个堆,分别叫mat_heap3.hprof和mat_heap4.hprof

注意:mat_heap3.hprof和mat_heap4.hprof是用AS 重新抓取的时间间隔较近的两个堆

  1. 用mat打开mat_heap3.hprof,和mat_heap4.hprof

  2. 按照问题6,输出消耗内存最大的部分。下面是mat_heap3.hprof的报告。
    在这里插入图片描述

从中,我们看到,占据内存最大的首要对象是int数组。接下来我们手动分析两个堆中的int数组之间的差距——即mat_heap4.hprof比mat_heap3.hprof多了哪几个int数组

  1. 点击mat_heap3.hprof的统计信息,即标记2.然后选中int[]。右键列出所有的对象。如下图
    在这里插入图片描述

  2. 点击操作历史记录栏,右键list_objects… 然后点击add to compare basket。如下图
    在这里插入图片描述

  3. 因为我们需要比较两个heap堆的int[]情况,因此选中mat_heap4.hprof之后,按照步骤3,4做同样操作。将会在compare basket窗口两个需要比较的对象。然后点击感叹号,开始比较即可。如下:
    在这里插入图片描述

对测试结果,进行简单排序,shallow_heap #1 升序排列。即可展示heap3中没有而heap4中具有的对象。这也是从抓取heap3时刻,到抓取heap4时刻之间,堆中多出来的int数组对象。为前排的10个对象。

按照前文的问题2即可查看其引用链,从而分析被谁持有,为何没有被释放掉。

在第2步中,输出的top comsumer除了int数组以外,还有其他的对象,因此按照步骤3,4,5即可进行两个堆的比较。我们已经以int[]为例子,做了详细说明,就不再一一比较。

除了使用top comsumer辅助定位需要比较的对象以外,还可以对任何怀疑的对象进行比较。步骤完全相同。

至此,MAT的使用介绍完毕。

MAT弥补了AS在内存分析上的如下不足:

  • 无法自定义Retained Set(这对于大型应用很有用)
  • 无法进行地址查找
  • 无法进行堆之间的比较
  • 无法按照需要进行排序
  • 无法按照需要进行过滤等

虽然MAT已经足够强大,但是依然还有一个内存问题,悬而未决——怎么才能知道这些内存泄露是由哪一个线程触发,它们又有怎样的调用栈?

在多线程编程中,对象的泄露,即可能是对象之间的引用不合理,也可能是线程之间的逻辑不合理,如生产线程和消费线程不够合理等等。MAT无法解决Android线程所带来的内存泄露。

接下里,请期待如何用工具找到这种多线程带来的内存泄露。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.hqwc.cn/news/66837.html

如若内容造成侵权/违法违规/事实不符,请联系编程知识网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

用python来爬取某鱼的商品信息(2/2)

目录 上一篇文章 本章内容 设置浏览器为运行结束后不关闭(可选) 定位到搜索框的xpath地址 执行动作 获取cookie 保存为json文件 修改cookie的sameSite值并且导入cookie 导入cookie(出错) 导入cookie(修改后&…

arcgis pro3.0-3.0.1-3.0.2安装教程大全及安装包下载

一. 产品介绍: ArcGIS Pro 这一功能强大的单桌面 GIS 应用程序是一款功能丰富的软件,采用 ArcGIS Pro 用户社区提供的增强功能和创意进行开发。 ArcGIS Pro 支持 2D、3D 和 4D 模式下的数据可视化、高级分析和权威数据维护。 支持通过 Web GIS 在一系列 …

PHP智能人才招聘网站mysql数据库web结构apache计算机软件工程网页wamp

一、源码特点 PHP智能人才招聘网站 是一套完善的web设计系统,对理解php编程开发语言有帮助,系统具有完整的源代码和数据库,系统主要采用B/S模式开发。 下载地址 https://download.csdn.net/download/qq_41221322/88199392 视频演示 PH…

《Kubernetes知识篇:常见面试题汇总》

正在不断地完善中,预计1个月的时间完成,覆盖整个Kubernetes知识面总结! 一、概述 1、简述什么是 Kubernetes? kubernetes(常简称k8s),是一个 为容器化应用提供自动化部署、扩展和管理的开源平台…

cs231n assignment2 q5 PyTorch on CIFAR-10

文章目录 嫌啰嗦直接看源码Q5 :PyTorch on CIFAR-10three_layer_convnet题面解析代码输出 Training a ConvNet题面解析代码输出 ThreeLayerConvNet题面解析代码输出 Train a Three-Layer ConvNet题面解析代码输出 Sequential API: Three-Layer ConvNet题面解析代码输出 CIFAR-1…

React Native 图片组件基础知识

在 React Native 中使用图片其实跟 HTML 中使用图片一样简单,在 React Native 中我们使用Image组件来呈现图片的内容,其中主要的属性有:source。这个属性主要是设置图片的内容,它可以是网络图像地址、静态资源、临时本地图像以及本…

nginx基于主机和用户访问控制以及缓存简单例子

一.基于主机访问控制 1.修改nginx.conf文件 2.到其他主机上测试 (1)191主机 (2)180主机 二.基于用户访问控制 1.修改nginx.conf文件 2.使用hpasswd为用户创建密码文件,并指定到刚才指定的密码文件webck 3.测试…

SQL注入之Oracle注入

SQL注入之Oracle注入 7.1 SQL注入之Oracle环境搭建 前言 Oracle Database,又名Oracle RDBMS,或简称Oracle。是甲骨文公司的一款关系数据库管理系统。它是在数据库领域一直处于领先地位的产品。可以说Oracle数据库系统是世界上流行的关系数据库管理系统…

如何将安卓 Gradle 模块打包发布到本地 Maven 仓库

文章目录 具体流程 笔者的运行环境: Android Studio Flamingo | 2022.2.1 Android SDK 33 Gradle 8.0.1 JDK 17 Android 的 Gradle 项目与一般的 Gradle 项目是不同的,因此对将 Gradle 模块打包发布到本地 Maven 仓库来说,对普通 Gradle …

【CTF-MISC】1和0的故事(二维码定位点补全)

题目链接:https://ctf.bugku.com/challenges/detail/id/216.html 文件中得到一个01方阵,可以在010 Editor中高亮设置将1涂为黑色、0涂为白色,如下图所示。 截图以后调整大小再加入三个定位点即可得到二维码。 扫描即可得到答案。 要注意的是…

轧钢传动控制系统液压比例阀控制器

轧钢传动控制系统是用于控制轧钢机械的电气系统,包括调速和控制系统两部分。 调速系统主要用来平滑调节转速,其核心部件是直流电动机调速单元。控制系统主要用于调节和稳定轧机的工作状态,使轧制过程始终处于最佳工作状态,其核心…

Java-类型和变量(基于C语言的补充)

一个简单的Java程序 args){ System.out.println("Hello,world"); } }通过上述代码,我们可以看到一个完整的Java程序的结构,Java程序的结构由如下三个部分组成: 1.源文件(扩展名为*.java):源文件带有类的定义…