HarmonyOS开发探索:使用Snapshot Insight分析ArkTS内存问题

  1.  识别内存问题

    当怀疑应用存在内存问题的时候,首先使用DevEco Profiler的Allocation Insight来度量内存在问题场景下的大小变化以及整体趋势,初步定界问题出现的位置(Native Heap/ArkTS Heap/dev等)。

    在初步识别内存问题出现的位置时,录制时需要将Allocation Insight中的后两条泳道取消勾选,只录制Memory这一条泳道。

    (注:因为另外两条泳道会开启对内存分配、内存对象的抓取,这些功能会带来额外的开销,可能会对我们初步定界问题产生噪音,阻碍分析,故先排除)

    cke_1205.png

    录制过程中,尽可能多的触发会导致内存问题的操作,将问题放大,便于快速定界问题点。复现完成后,结束录制,选中Memory泳道(直接选中泳道详情区域会展示完整的泳道数据),查看详情区域的数据 (注:详情区域数据采用PSS的维度衡量,数据近似于使用`hidumper --mem $pid`的第一列PSS值)

    cke_6725.png

    通过详情区域的详细内存占用数值,我们能够大致定界出有哪些位置的内存可能存在问题。

    因为本文主要介绍如何定位ArkTS的内存问题,故只关心ArkTS Heap相关的部分。从表格的数据中发现,ArkTS Heap有不少的上涨,这说明在方舟虚拟机内的堆内存上可能存在内存泄漏问题,需要进一步分析。

    cke_8190.png

  2. 分析ArkTS Heap

    ArkTS在编译后会生成JS代码,运行在方舟虚拟机中。分析虚拟机的堆内存问题时会用到内存快照(Heap Snapshot/Heap Dump)技术,DevEco Profiler提供了分析内存快照的Snapshot Insight。

    cke_10246.png

    点击领取→纯血鸿蒙Next全套最新学习资料(安全链接,放心点击希望这一份鸿蒙学习资料能够给大家带来帮助,有需要的小伙伴自行领取,

    在使用Snapshot分析时,通常会使用三快照技术(Three Snapshot Technique),通过内存快照的对比视图将某两次快照之间分配且仍然驻留的内存筛选出来,这些对象中的一部分就可能是导致内存泄漏的对象。通用的流程为:

    打开应用,初始化场景 (触发GC)-> 拍摄第一次Snapshot作为基准 -> 多(N)次触发内存泄漏操作 -> 拍摄第二次堆快照 -> 触发主动GC -> 拍摄第三次堆快照。由于方舟虚拟机提供了在获取堆快照之前自动GC的功能,因此我们可以将上述流程简化为两步,同时加上Profiler的录制功能,整体流程为:

    打开应用,初始化场景 -> 开启录制Snapshot Insight-> 拍摄第一次Snapshot作为基准 -> 多(N)次触发内存泄漏操作 -> 拍摄第二次堆快照 -> 结束录制。

    录制完成后,会得到如下图所示的数据:

    cke_11741.png

    录制过程中,我们采集了两次堆快照,对应在Profiler的界面上就是两个紫色的条块,每一个条块内的数据都是当前的虚拟机堆快照。条块上的数字大小代表的是虚拟机堆内存的实际占用

    由于在每次拍摄堆快照之前,虚拟机都会触发GC,所以理论上堆快照内存在的对象都是当前虚拟机已经无法GC掉的对象,所以我们可以将两个堆快照进行比较,来查看哪些对象是我们在触发问题场景时新增了且不能释放的。

    点击Snapshot Insight面板的Comparison页签,将两次Snapshot进行比较,如下图。图中数据的含义为以Snapshot1作为基准,Snapshot2对比Snapshot1的数据变化量。

    cke_13426.png

    在触发内存问题场景时将问题触发N次,在比较视图中首先就去找与N强相关、与业务代码强相关的constructor,首先来分析这些对象是否正常。

    首先介绍一下Snapshot比较视图中各项数据的含义,如下图:

    cke_15760.png

    在找到相关的业务关联的对象后,可以从右侧More区域的Retainers里面一层层去寻找、排查在引用链上的可疑对象(一般指与业务代码关联的对象,例如上图中的setData)。

    当发现了引用链上的业务对象时,就可以通过对象索引功能(IDE正在实现)可以一环一环找到各个对象的引用关系,通过排查在引用链上的对象传递关系,在代码中分析相关的逻辑来找到内存泄漏的位置。

  3. 应用代码排查

    具备了通用的分析能力,就需要根据业务场景来排查代码,分析代码中出现问题的位置。

    第一步,就是先缩小问题场景,让场景尽可能的单一,最好是单一操作单一组件出现问题。涉及的代码越少,定位效率越高

    第二步,开始排查代码,首先需要排查的模块就是在上面提到的Snapshot分析中所找出到的问题场景中两个Snapshot对比里增加的与业务代码相关的对象以及其引用链(这里在排查引用链时,可以参考:ArkTS内存泄露分析,在引用链中有一些对象是虚拟机内部的,基本不需要开发者关心)。

    这一步在代码场景比较单一的时候,可以结合引用逻辑与代码来一起分析是什么原因造成的,例如闭包被全局对象持有无法释放。结合目前的经验来看,从引用链上虽然无法直接定位到代码具体位置和原因,但是可以分析到一些代码关联性的。

    但是在引用链上也很可能会挂载一些ArkUI相关的对象,如果定位到大量的应用对象最终的引用关系都是引用到了ArkUI对象上,可能需要找到相关的框架同事来协助定位。

    这一步中可能有两个问题:

    1. 对象实例以及引用链上有很多对象都和业务代码相关联,应该从哪一个下手。

    2. 对象引用链实在太过复杂,具体要看哪里,怎么一步步往下看。

    针对这两个问题:

    1. 关联对象多,这时候不要发散,力出一孔,优先解决一个问题,顺带着可能就解决掉了一串问题,然后再根据可能涉及到的多个模块逐个攻破

    2. 参考上面的Ark调优工具指南,使用“深度优先遍历”的方法先分析一条引用链,找到其中的可疑点,再慢慢地发散到其他的引用链上,找出一些共性的对象,最终汇总起来再集中审视所有的可疑对象

    第三步,通过在上面步骤中分析的代码,最好相关模块的开发人员来走读一遍代码,通过白盒来分析可能存在的问题点。如果实在模块逻辑太过复杂,那就只有请出注释大法,二分的来定位问题位置。

  4. 实践

    这里使用一个某视频应用内存泄漏的问题来简单介绍具体的问题定位方法。

    问题出在视频应用的搜索页上,在点击进入搜索页搜索内容后退出搜索页,发现内存增长不会回退,且不断操作进入/退出时内存数据会一直增加,因此怀疑这步操作存在内存泄漏。

    采用章节2中提到的两步Snapshot法:

    1. 打开应用,在初始化的页面上拍摄一次ArkTS堆内存快照。

    2. 反复进入搜索页搜索内容,一共触发6次,并在搜索完之后推出搜索页回到主页(步骤1)的状态。

    3. 拍摄第二次ArkTS堆内存快照,拍摄完成后停止录制等待解析完毕。

    快照解析完成后,即可使用对比视图查看在两次相同状态下的应用内存区别,下面是对比视图:

    cke_17628.png

    结合业务逻辑,从对比视图中发现,MainSearch这个搜索逻辑所对应的业务对象在两次Snapshot之间增加了4个,并且是虚拟机无法GC回收掉的对象(因为虚拟机在做dump之前自动触发一次Full GC),而从B站的业务逻辑中确认,该对象在退出搜索页面时就应该被销毁,因此基本可以确定该对象产生了泄漏。

    接下来就要分析为什么会这个对象不会被GC回收掉,在方舟虚拟机中,对象不会被GC回收的根本原因是从GC Root到该对象有至少一条引用链,导致该对象间接甚至直接被GC Root引用,虚拟机在做可达性分析时,发现该对象被GC Root引用,因此不会回收该对象。接下来就需要借助工具中的引用链来分析为什么对象会被GC Root引用,找出其中的引用关系并解决掉错误的引用关系,以释放相应的内存。虚拟机GC详细介绍可参考:解密方舟的高性能内存回收技术——HPP GC。

    cke_19520.png

    打开该构造器所对应的树状结构,其子节点均为该构造器对应的实例对象,也即在这次快照中仍然存活的对象,再将该对象节点展开,其下方节点为对象的属性(Fields)以及引用链(Retainers),点击该对象即可在Reatiners中分析其引用链。

    cke_21371.png

    引用链中有个重要信息是Distance,即该节点距离GC Root的距离(所需要经过的节点个数),我们在分析引用链上的对象问题时,通常会逐步找Distance越来越小的对象,以对该对象到GC Root上对象的进行分析,如上图所示,就是一条从泄漏对象(Main Search)到GC Root的引用链。下面挑选其中一小部分来介绍如何分析引用链。

    cke_23440.png

    图中是一个顺序展开的树形引用链结构,其中每一行标注了字母,后面用字母代替该行的数据。

    引用链在树形结构的展示中是一个反向的逻辑,即下面一行的属性引用了上面一行的对象,拿A和B举例,上图中的关系就代表着A中RelationCenter这个对象的_instance属性引用了B中的RelationCenter JSObject,而B中RelationCenter这个对象的subscribers属性又引用了JSArray对象,再往上分析以此类推。

    反过来也可以这么理解:B中RelationCenter JSObject就是A中RelationCenter对象的_instance属性。

    用伪代码可以描述为:

    A:RelationCenter._instance = B:RelateionCenter JSObjectB:RelateionCenter JSObject.subscribers = C:JSArrayC:JSArray[7] = D:RelationButton.anonymous(line:84)

    通过这个引用关系,可以大体上确定出代码的变量引用逻辑,接下来就要去白盒分析代码的问题所在,即这些引用是否合理,若不合理,需要解决这些引用关系

    在此视频应用的这个问题中,分析发现这里在 GC Root距离为 7 的节点上(上图中D), 看到 RelationButton anonymous(line:84)以及RelationCenter相关信息(如果需要查看该对象的详细信息,可以点击这一行字符后面的蓝色按钮,跳转到对象详情面板),

    我们打开项目在编译后的文件中(build目录下的ts文件)找到 RelationButton的84行,分析逻辑发现是一个 subscriber,首先考虑是否是因为忘记解绑这个定位导致问题,然后去自己的 ets 代码找问题。

    最终定位到相关的源码文件发现是因为没有解除相关代码的订阅导致内存泄漏,添加解绑逻辑后再次抓取快照测试,该引用链消失,这个问题点解除,接下来以相同的方式分析其余类似问题。

    上面的例子只是简单介绍如何通过引用链来分析可疑的内存泄漏对象的方法,并未过多描述其中的分析排查思路和逻辑,总的来说,在应用侧排查内存问题时,主要有以下几个关注点:

    1. Snapshot的对比视图中,优先观察与当前问题场景强相关的业务对象,虚拟机内部对象以及一些基础对象(例如ArkInternelXXX/(array)/GLOBAL等等)可以先不关心,可以使用过滤功能过滤出业务代码相关的对象(例如使用com.huawei进行过滤)。

    2. 在分析引用链的过程中,引用链上可能掺杂了一些虚拟机内部的对象(因为虚拟机需要使用一些内部对象或类型来管理/表达业务对象),所以引用链的分析过程中也可以优先关注业务侧的对象,先忽略掉其中的虚拟机内部对象(虚拟机内部对象的描述,可以参考:ArkTS内存泄露分析)。

    3. Snapshot中展示的对象可能非常多,这可能是由于某一条引用链上引用了很多的对象所导致的,不要怕,逐个解决其中的与当前业务逻辑最相关的对象,其他的对象可能随之就一起解决掉了,所以优先解决业务对象以及与问题复现场景下最强相关的对象的引用逻辑,其余对象逐步再进行优化。

  5. 结语

    问题通常会在开发的过程中逐渐积累,到最终暴露出来时可能已经涉及了多个模块、多种逻辑,各种逻辑互相耦合,导致分析的难度大大增加。

    这种情况下,我们建议把性能相关的工作也能做到平时,在开发态也去关心程序的性能问题。例如,刚写了一个很长的引用关系、增加了一些注册实例的逻辑或者做了一些父子组件的变量传递,这种时候就可以去结合逻辑自己设想一下,会不会引发一定的性能问题,甚至可以在平时就用调优工具来自测试。这样做到每个开发阶段都保证了性能的可靠,那么在项目日益增大的同时,性能问题也不会严重到离谱、无法分析。

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

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

相关文章

CentOS中使用SSH远程登录

CentOS中使用SSH远程登录 准备工作SSH概述SSH服务的安装与启动建立SSH连接SSH配置文件修改SSH默认端口SSH文件传输 准备工作 两台安装CentOS系统的虚拟机 客户机(192.168.239.128) 服务器(192.168.239.129) SSH概述 Secure S…

Mustango——音乐领域知识生成模型探索

Mustango:利用领域知识的音乐生成模型 论文地址:https://arxiv.org/pdf/2311.08355.pdf 源码地址:https://github.com/amaai-lab/mustango 论文题为**“**利用音乐领域知识开发文本到音乐模型’Mustango’”。它利用音乐领域的知识从文本指…

K 近邻、K-NN 算法图文详解

1. 为什么学习KNN算法 KNN是监督学习分类算法,主要解决现实生活中分类问题。根据目标的不同将监督学习任务分为了分类学习及回归预测问题。 KNN(K-Nearest Neihbor,KNN)K近邻是机器学习算法中理论最简单,最好理解的算法…

钉钉开放AI生态战略的真正价值到底是什么?很多人都没看懂

来源: 首席数智官 hello 大家好,我们是数字化领军者都在看的首席数智官。 关注我,每天给你讲一个商业案例。 今天我们要给你讲的是:钉钉开放AI大模型生态的战略意义到底是什么? 「谁先赢得苹果,谁就赢得…

AI大模型日报#0701:Meta发布LLM Compiler、扒一扒Sora两带头人博士论文

导读:AI大模型日报,爬虫LLM自动生成,一文览尽每日AI大模型要点资讯!目前采用“文心一言”(ERNIE-4.0-8K-latest)生成了今日要点以及每条资讯的摘要。欢迎阅读!《AI大模型日报》今日要点&#xf…

09 - matlab m_map地学绘图工具基础函数 - 绘制区域填充、伪彩色、加载图像和绘制浮雕效果的有关函数

09 - matlab m_map地学绘图工具基础函数 - 绘制区域填充、伪彩色、加载图像和绘制浮雕效果的有关函数 0. 引言1. 关于m_pcolor2. 关于m_image3. 关于m_shadedrelief4. 关于m_hatch5. 结语 0. 引言 本篇介绍下m_map中区域填充函数(m_hatch)、绘制伪彩色图…

2.2章节python的变量和常量

在Python中,变量和常量有一些基本的概念和用法,但需要注意的是,Python本身并没有内置的“常量”类型。然而,程序员通常会遵循一种约定,即使用全部大写的变量名来表示常量。 一、变量 在Python中,变量是一…

毫米波雷达深度学习技术-2.1~2.2深度度量学习和成对方法

2 深度度量学习 有几种雷达应用程序旨在对一组预定义的类别进行分类,例如不同的人类活动或手势。然而,在实际环境中,存在的类不仅仅是预定义的类,这就把问题变成了一个开放集的分类任务。开放集分类意味着网络应该能够检测输入是否…

Chapter 8 Feedback

Chapter 8 Feedback 这一章我们介绍feedback 反馈运放的原理. 负反馈是模拟电路强有力的工具. 8.1 General Considerations 反馈系统如下图所示 Aolamp open-loop gain即开环增益. Aolxo/xi β \beta β 是 feedback factor, 注意方向. β x f x o \beta\frac{x_{f}}{x_{o…

一、课程介绍,基础—环境安装、判断、循环语句等(爬虫及数据可视化)

一、课程介绍,基础—环境安装、判断、循环语句等(爬虫及数据可视化) 1. 课程介绍1.1 相关内容1.2 学习目标1.3 学习内容安排 2. python2.1 环境配置2.2 标识符和关键字2.3 运算符2.4 判断语句2.5 循环语句 1. 课程介绍 1.1 相关内容 10天的…

【pytorch11】高阶操作

高阶操作 WhereGather where 三个参数,第一个是condition,第二个参数是源头A,第三个参数是源头B,也就是说有两项数据A和B,C有可能来自于A也有可能来自于B,如果全部来自于A的话直接赋值给A,如果…

算法金 | Transformer,一个神奇的算法模型!!

大侠幸会,在下全网同名「算法金」 0 基础转 AI 上岸,多个算法赛 Top 「日更万日,让更多人享受智能乐趣」 抱个拳,送个礼 在现代自然语言处理(NLP)领域,Transformer 模型的出现带来了革命性的变…

无线物联网练习题

文章目录 选择填空简答大题 选择 不属于物联网感知技术的是(A) A:ZigBee B:红外传感器 C:FRID D:传感器 ZigBee是一种无线通信技术,虽然它常用于物联网中作为设备之间的通信手段,但它本身并不是一种感知技术 关于物联网于与互联网的区别的描述&#xff…

【机器学习】基于Transformer的迁移学习:理论与实践

引言 在机器学习领域,迁移学习已成为提升模型训练效率和性能的重要策略,特别是在标注数据稀缺的场景下。Transformer模型自2017年由Google提出以来,在自然语言处理(NLP)领域取得了突破性进展,并逐渐扩展到…

Zuul介绍

Zuul 是 Netflix 开源的一个云平台网络层代理,它主要用于路由、负载均衡、中间件通信和动态路由。Zuul 本质上是一个基于 JVM 的网关,它提供了以下功能: 1.路由:Zuul 允许客户端和服务器之间的所有入站和出站请求通过一个中心化的…

小红书怎么保存无水印图?

使用小红书APP长按保存的图片代有水印,很多人想知道保存小红书无水印图片的方法。本文教你如何保存到无水印的小红书图片,但是请注意不要侵犯作者图片的版权。 小红书怎么保存无水印图? 1、手机上打开小红书APP; 2、打开后&#…

昇思25天学习打卡营第13天|BERT

一、简介: BERT全称是来自变换器的双向编码器表征量(Bidirectional Encoder Representations from Transformers),它是Google于2018年末开发并发布的一种新型语言模型。与BERT模型相似的预训练语言模型例如问答、命名实体识别、自…

2.3章节Python中的数值类型

1.整型数值 2.浮点型数值 3.复数   Python中的数值类型清晰且丰富,主要分为以下几种类型,每种类型都有其特定的用途和特性。 一、整型数值 1.定义:整数类型用于表示整数值,如1、-5、100等。 2.特点: Python 3中的…

卡尔曼滤波公式推导笔记

视频见B站上DR_CAN的卡尔曼滤波器 【卡尔曼滤波器】3_卡尔曼增益超详细数学推导 ~全网最完整_哔哩哔哩_bilibili

动手学深度学习5.6 GPU-笔记练习(PyTorch)

以下内容为结合李沐老师的课程和教材补充的学习笔记,以及对课后练习的一些思考,自留回顾,也供同学之人交流参考。 本节课程地址:17 使用和购买 GPU【动手学深度学习v2】_哔哩哔哩_bilibili 本节教材地址:5.6. GPU —…