| |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
-> 移动开发 -> Flutter 上的内存泄漏监控,2021京东Android面试真题 -> 正文阅读 |
|
[移动开发]Flutter 上的内存泄漏监控,2021京东Android面试真题 |
4、泄漏检测实现有了 vm_service 之后,我们就可以用它来弥补 api,它的返回值是 Instance ,内部的 现在的问题是 api 参数中的 isoateId 和 objectId 是啥,根据我前面介绍的 id 相关内容,它是对象在 vm_serive 中的标识符。也就是我们只有通过 vm_service 才可以获取到这两个参数。 IsolateId 的获取Isolate(隔离区)是 dart 里面的一个非常重要的概念,基本上一个 isolate 相当于一个线程,但是和我们平常接触的线程不同的是:不同 isolate 之间的内存不共享。 因为有了上述特性,我们在查找对象的时候也要带上 isolateId。通过 vm_service 的 那么怎么筛选出我们想要的 isolate 呢?这里简单起见只筛选主 isolate,这部分的筛选可以查看 dev_tools 的源码: service_manager.dart#_initSelectedIsolate 函数。 ObjectId 的获取我们要获取的 objectId 就是 expando 在 vm_service 中的 id,这里可以把问题扩展下: 如何获取指定对象在 vm_service 中的 id? 这个问题比较麻烦,vm_service 中没有实例对象和 id 转换的 api,有个 没有好办法了吗?其实我们可以借助 Library 的 顶级函数(直接写在当前文件,不在类中,例如 main 函数) 来实现该功能。
vm_service 有个 invoke(isolateId, targetId, selector, argumentIds) api,可以用来执行某个常规函数(getter、setter、构造函数、私有函数属于非常规函数),其中如果 targetId 是 Library 的 id,那么 invoke 执行的就是 Library 的顶级函数。 有了 invoke Library 顶级函数的路径,就可以用它实现对象转id 了,代码如下:
对象泄漏判断现在我们已经可以获取到 expando 实例在 vm_service 中的 id 了,接下来就简单了 先通过 vm_service 获取到 遍历 强制 GC文章开头说到,如果要判断对象是否泄漏,需要在 Full GC 之后判断弱引用是否还在。有没有办法手动触发 gc 呢? 答案是有的,vm_service 虽然没有强制 gc 的 api,但是 dev_tools 的内存图标右上角有个 GC 的按钮,我们仿照着它来操作就行!dev_tools 是调用了 vm_service 的 getAllocationProfile(isolateId, gc: true) api 来实现手动 gc 的。 至于这个 api 触发的是不是 FULL GC,并没有说明,我测试触发的都是 FULL GC,如果要确定在 FULL GC 之后检测泄漏,可以监听 gc 事件流,vm_service 提供了该功能。 至此为止,我们已经可以实现泄漏的监控,而且可以获取到泄漏目标在 vm_serive 中的 id 了,下面就开始获取分析泄漏路径。 5、获取泄漏路径关于泄漏路径的获取,vm_service 提供了一个 api 叫 getRetainingPath(isolateId, objectId, limit) 。直接使用此 api 就可以获取到泄漏对象到 gc root 的引用链信息,是不是感觉很简单?不过光这样可不行,因为它有以下几个坑点: Expando 持有问题如果在执行
此问题很好解决,注意下在前面泄漏检测完之后,释放掉 expando 就行。 id 过期问题Instance 类型的 id 和 Class、Library、Isolate 这种 id 不一样,是会过期的。vm_service 中对于此类临时 id 的缓存容量默认大小是 8192,是一个循环队列。 因为此问题的存在,我们在检测到泄漏的时候,不能只保存泄漏对象的 id,需要保存原对象,而且不能强引用持有对象。所以这里我们还是需要使用 expando 来保存我们检测到的泄漏对象,等到需要分析泄漏路径的时候,再把对象专为 id。 6、1.9.1 framework 上的内存泄漏完成了泄漏检测和路径获取之后,得到了一个简陋的 leakcanary 工具。当我在 1.9.1 版本的 framework 下测试此工具的时候发现,我观测一个页面它就泄漏一个页面!!!
也就是 1.9.1 framework 里面存在着泄漏,而且此泄漏会泄漏整个页面。 接下来开始排查泄漏原因,这里就碰到一个问题:泄漏路径太长。。。 结论:直接根据 vm_service 返回的数据是很难分析问题来源的,需要对泄漏路径的信息二次处理下。 如何缩短引用链首先看下泄漏路径为什么会这么长,通过观测返回的链路后发现,绝大部分的节点都是 flutter UI 组件节点(例如:widget、element、state、renderObject)。 也就是说引用链经过了 flutter 的组件树,玩过 flutter 的应该都知道 flutter 组件树的层次是非常深的。既然引用链长的原因是因为包含了组件树,而且组件树基本都是成块出现的,那我们只要把引用链中的节点根据类型来分类、聚合,就可以大幅缩短泄漏路径了。 分类根据 flutter 的组件类型,将节点分为以下几种类型:
聚合节点的分类做好了之后,就可以把相同类型的节点聚合一下。这里提下我的聚合方式 把 collection 类型的节点看成了连接节点,相邻的相同节点合并到一个集合内,如果两个相同类型的集合中间是通过 collection 节点相连的,就继续把这两个集合合并成一个集合,递归进行
继续排查 1.9.1 framework 的泄漏问题,路径虽然缩短了,可以找到问题大致出现在
介于上述两个痛点,还需要对泄漏节点的信息做扩展处理:
排查 1.9.1 framework 泄漏根源 |
|
移动开发 最新文章 |
Vue3装载axios和element-ui |
android adb cmd |
【xcode】Xcode常用快捷键与技巧 |
Android开发中的线程池使用 |
Java 和 Android 的 Base64 |
Android 测试文字编码格式 |
微信小程序支付 |
安卓权限记录 |
知乎之自动养号 |
【Android Jetpack】DataStore |
|
上一篇文章 下一篇文章 查看所有文章 |
|
开发:
C++知识库
Java知识库
JavaScript
Python
PHP知识库
人工智能
区块链
大数据
移动开发
嵌入式
开发工具
数据结构与算法
开发测试
游戏开发
网络协议
系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程 数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁 |
360图书馆 购物 三丰科技 阅读网 日历 万年历 2025年1日历 | -2025/1/31 6:13:11- |
|
网站联系: qq:121756557 email:121756557@qq.com IT数码 |