当前位置: 首页 > news >正文

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线程所带来的内存泄露。

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

相关文章:

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

android 如何分析应用的内存(十七)——使用MAT查看Android堆 前一篇文章,介绍了使用Android profiler中的memory profiler来查看Android的堆情况。 如Android 堆中有哪些对象,这些对象的引用情况是什么样子的。 可是我们依然面临…...

Spring 使用注解储存对象

文章目录 前言存储 Bean 对象五大注解五大注解示例配置包扫描路径读取bean的示例 方法注解 Bean Bean 命名规则重命名 Bean 前言 通过在 spring-config 中添加bean的注册内容,我们已经可以实现基本的Spring读取和存储对象的操作了,但在操作中我们发现读…...

一、初始 Spring MVC

文章目录 一、回顾 MVC 模式二、初始 Spring MVC2.1 Spring MVC 核心组件2.1.1 前端控制器(DispatcherServlet)2.1.2 处理器映射器(HandlerMapping)2.1.3 处理器适配器(HandlerAdapter)2.1.3 后端控制器&am…...

《爬虫》爬取页面图片并保存

爬虫 前言代码效果 简单的爬取图片 前言 这几天打算整理与迁移一下博客。因为 CSDN 的 Markdown 编辑器很好用 ,所以全部文章与相关图片都保存在 CSDN。而且 CSDN 支持一键导出自己的文章为 markdown 文件。但导出的文件中图片的连接依旧是 url 连接。为了方便将图…...

【项目部署】JavaScript解析JSON解析报错Unexpected token xxx is not valid JSON

问题背景 这个报错发生在之前部署的一个前后端分离的项目中。后端使用的Spring Boot,前端使用的JavaScript,前后端交互使用Thymeleaf框架。 现象 项目组的另一个小伙伴说,突然有个页面打不开了,整个页面全空白。我F12打开浏览器…...

做接口测试如何上次文件

在日常工作中,经常有上传文件功能的测试场景,因此,本文介绍两种主流编写上传文件接口测试脚本的方法。 首先,要知道文件上传的一般原理:客户端根据文件路径读取文件内容,将文件内容转换成二进制文件流的格式…...

Java SPI机制详解-01

1. 概述 SPI(Service Provider Interface),是 Java 6 引入了一个内置功能,实现服务提供发现和加载机制,使之与特定接口的匹配。 SPI 机制的核心思想就是 解耦 ,将装配的控制权移到程序之外,这…...

由浅入深C系列六:C中实现字符串trim的功能

C中实现字符串trim的功能 简介设计思路代码实现运行效果 简介 一个项目中,需要用c语言实现对字符串中的字定字符进行过滤并从字符串的删除,查询了C语言的基本库,没有发现有这样的函数,于是发挥程序员的主观能力性,自力…...

博客网站添加复制转载提醒弹窗Html代码

网站如果是完全禁止右键(复制、另存为等)操作,对用户来说体验感会降低,但是又不希望自己的原创内容直接被copy,今天飞飞和你们分享几行复制转载提醒弹窗Html代码。 效果展示: 复制以下代码,将其…...

ubuntu下nfs服务安装

操作系统:ubuntu22.04.2 一、服务端安装与配置 1、在服务端安装nfs服务端组件 sudo apt install nfs-kernel-server 2、创建共享目录share并且授权所有人可以访问 sudo mkdir /shared sudo chmod -R 777 /shared 3、配置nfs sudo vim /etc/exports 这将允许…...

Unity框架学习--2

接上文 IOC 容器是一个很方便的模块管理工具。 除了可以用来注册和获取模块,IOC 容器一般还会有一个隐藏的功能,即: 注册接口模块 抽象-实现 这种形式注册和获取对象的方式是符合依赖倒置原则的。 依赖倒置原则(Dependence I…...

WebRTC音视频通话-实现GPUImage视频美颜滤镜效果iOS

WebRTC音视频通话-实现GPUImage视频美颜滤镜效果 在WebRTC音视频通话的GPUImage美颜效果图如下 可以看下 之前搭建ossrs服务,可以查看:https://blog.csdn.net/gloryFlow/article/details/132257196 之前实现iOS端调用ossrs音视频通话,可以查…...

82. 删除排序链表中的重复元素 II

题目链接:力扣(LeetCode)官网 - 全球极客挚爱的技术成长平台 解题思路:设置一个新的哑元节点result,作为头节点,将head中不重复地节点依次链接到哑元节点后面,最后返回result.next 初始值&…...

centos 7.x 单用户模式

最近碰到 centos 7.9 一些参数设置错误无法启动系统的情况,研究后可以使用单用户模式进入系统进行恢复操作。 进入启动界面,按 e ro 替换为 rw init/sysroot/bin/sh 替换前 替换后 Ctrl-x 进行重启进入单用户模式 执行 chroot /sysroot 可以查看日…...

取证--理论

资料: 各比赛 Writeup : https://meiyacup.cn/Mo_index_gci_36.html 哔站比赛复盘视频: https://space.bilibili.com/453117423?spm_id_from333.337.search-card.all.click 自动分析取证四部曲 新建案例添加设备自动取证制作报告 取证大…...

Tik Tok娱乐+电商MCN怎么做?

在美国外的热门市场中,TikTok 主要做的区域市场包括中东、拉美、欧洲和东亚,而这里面适合做电商的其实并不多。 欧洲、东亚都属于成熟市场,且 TikTok 本身在欧洲面临 DSA 法案更严格的审查,与在英国相同,欧洲各市场消…...

java 自定义xss校验注解实现

自定义一个注解Xss。名字随意 import javax.validation.Constraint; import javax.validation.Payload; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Targe…...

Selenium图片滑块验证码

因为种种原因没能实现愿景的目标,在这里记录一下中间结果,也算是一个收场吧。这篇文章主要是用selenium解决滑块验证码的个别案列。 思路: 用selenium打开浏览器指定网站 将残缺块图片和背景图片下载到本地 对比两张图片的相似地方&#…...

CAP理论与MongoDB一致性,可用性的一些思考

正文 大约在五六年前,第一次接触到了当时已经是hot topic的NoSql。不过那个时候学的用的都是mysql,Nosql对于我而言还是新事物,并没有真正使用,只是不明觉厉。但是印象深刻的是这么一张图片(后来google到图片来自这里&…...

lc2536.子矩阵元素加1

暴力解法:直接按照题目所示在矩阵的相应位置加一 时间复杂度:O(n2 * queries.length) 空间复杂度:O(1) 二维差分:创建二维差分数组,通过对差分数组的修改来影响原来的数组,最后还原 时间复杂度&#x…...

java面试场景提题:

以下是润色后的文章,结构更清晰,语言更流畅,同时保留了技术细节: 应对百倍QPS增长的系统设计策略 整体架构设计思路 面对突发性百倍QPS增长,系统设计需从硬件、架构、代码、数据四个维度协同优化: 硬件层…...

natapp 内网穿透失败

连不上网络错误调试排查详解 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 如何将DNS服务器修改为114.114.114.114_百度知道 连不上/错误信息等问题解决汇总 - NATAPP-内网穿透 基于ngrok的国内高速内网映射工具 nslookup auth.natapp.cnping auth.natapp.cn...

在Linux查看电脑的GPU型号

VGA 是指 Video Graphics Array,这是 IBM 于 1987 年推出的一种视频显示标准。 lspci | grep vga 📌 lspci | grep -i vga 的含义 lspci:列出所有连接到 PCI 总线的设备。 grep -i vga:过滤输出,仅显示包含“VGA”字…...

[特殊字符] 深入理解 Linux 内核进程管理:架构、核心函数与调度机制

Linux 内核作为一个多任务操作系统,其进程管理子系统是核心组成部分之一。无论是用户应用的运行、驱动行为的触发,还是系统调度决策,几乎所有操作都离不开进程的创建、调度与销毁。本文将从进程的概念出发,深入探讨 Linux 内核中进…...

发版前后的调试对照实践:用 WebDebugX 与多工具构建上线验证闭环

每次产品发版都是一次“高压时刻”。版本升级带来的不仅是新功能上线,更常伴随隐藏 bug、兼容性差异与环境同步问题。 为了降低上线风险,我们逐步构建了一套以 WebDebugX 为核心、辅以 Charles、Postman、ADB、Sentry 的发版调试与验证流程,…...

使用Caddy在Ubuntu 22.04上配置HTTPS反向代理

使用Caddy在Ubuntu 22.04上配置HTTPS反向代理(无域名/IP验证+密码保护) 一、 环境说明 环境说明:测试环境,生产环境请谨慎OS: Ubuntu 22.04.1 LTSCaddy版本:v2.10.0服务器IP: 192.168.3.88(内网)公网IP: 10.2.3.11(测试虚拟)代理端口: 9080后端服务: http://192.168.3…...

《探秘跨网段局域网IP广播:解锁网络通信的新姿势》

一、从基础出发:广播与跨网段 在计算机网络的世界中,广播域是一个至关重要的概念。简单来说,广播域是指网络中能接收任一台主机发出的广播帧的所有主机集合。当一台主机在广播域内发出一个广播帧时,同一广播域内的所有其他主机都可以收到该广播帧。在没有路由器或 VLAN 分割…...

PDF 转 Markdown

本地可部署的模型 Marker Marker 快速准确地将文档转换为 markdown、JSON 和 HTML。 转换所有语言的 PDF、图像、PPTX、DOCX、XLSX、HTML、EPUB 文件在给定 JSON 架构 (beta) 的情况下进行结构化提取设置表格、表单、方程式、内联数学、链接、引用和代…...

乐观锁与悲观锁的实现和应用

乐观锁与悲观锁:原理、实现与应用详解 在并发编程和数据库操作中,乐观锁和悲观锁是两种重要的并发控制策略,它们在原理、实现方式和应用场景上存在显著差异。下面我们将通过图文结合的方式,深入探讨这两种锁机制。 一、基本概念 1…...

金融系统渗透测试

金融系统渗透测试是保障金融机构网络安全的核心环节,它的核心目标是通过模拟攻击手段主动发现系统漏洞,防范数据泄露、资金盗取等重大风险。 一、金融系统渗透测试的核心框架 合规性驱动 需严格遵循《网络安全法》《数据安全法》及金融行业监管要求&am…...