从渲染原理出发探究Flutter内存泄漏(超详细)( 二 )
以ui.SceneBuilder一个例子了解下Dart是如何绑定c++对象实例 , 并且控制这个c++实例的析构工作 。
Dart层渲染过程是配置的layer渲染树 , 并且提交到c++层进行渲染的过程 。 ui.SceneBuilder便是这颗渲染树的容器
本文插图
- Dart代码调用构造函数ui.SceneBuilder()时 , 调用c++方法SceneBuilder_constructor
- 调用flutter::SceneBuilder的构造方法并生成c++实例sceneBuilder
- 因flutter::SceneBuilder 继承自内存计数对象RefCountedDartWrappable , 对象生成后会内存计数加1
- 将生成c++实例sceneBuilder使用Dart的API生成一个WeakPersitentHandle , 注入到Dart上下中 。 在这里之后 , Dart便可使用这个builder对象 , 便可操作这个c++的flutter::SceneBuilder 实例 。
- 程序运行许久后 , 当Dart虚拟机判断Dart 对象builder没有被任何其他对象引用时(例如简单的情况是被置空builder=null , 也称为无可达性) , 对象就会被垃圾回收器(Garbage Collection)回收释放 , 内存计数将会减一
- 当内存计数为0时 , 会触发c++的析构函数 , 最终c++实例指向的内存块被回收
更直白而言 , 只要C/C++实例对应的Dart对象能正常被GC回收 , C/C++所指向的内存空间便会正常释放 。
WeakPersistentHandle是什么
因为Dart对象在VM中会因为GC整理碎片化中经常移动 , 所以使用对象时不会直接指向对象 , 而是使用句柄(handle)的方式间接指向对象 , 再者c/c++对象或者实例是介乎于Dart虚拟机之外 , 生命周期不受作用域约束 , 且一直长时间存在于整个Dart虚拟机中 , 所以称为常驻(Persistent) , 所以WeakPersistentHandle专门指向生命周期与常在的句柄 , 在Dart中专门用来封装C/C++实例 。
在flutter官方提供的Observatory工具中 , 可以查看所有的WeakPersistentHandle对象
本文插图
其中Peer这栏也就是封装c/c++对象的指针
本文插图
Dart对象的可达性
Dart对象释放会被垃圾回收器(Garbage Collection)进行释放 , 是通过判定对象是否还有可达性(availability)来达到的 。 可达性是指通过某些根节点出发 , 通过对象与对象间的引用链去访问对象 , 如可通过引用链去访问对象 , 则说明对象有可达性 , 否则无可达性 。
黄色有可达性 , 蓝色无可达性
本文插图
难以察觉的内存泄漏
看到这里我们会发现一个问题 , 其实我们很难从Dart侧难感知C/C++对象的消亡 , 因为Dart对象无统一的如同C++类一样的析构函数 , 一旦对象因为循环引用等的原因被长期其他对象长期引用 , GC将无法将其释放 , 最终导致内存泄漏 。
将问题放大一点 , 我们知道flutter是一个渲染引擎 , 我们通过编写Dart语言构建出一颗Widget树 , 进而经过绘制等过程简化成Element树 , RenderObject树 , Layer树 , 并将这颗Layer树提交至C++层 , 进而使用Skia进行渲染 。
本文插图
如果某个Wigdet树或Element树的某个节点长期无法得到释放 , 将可能造成他的子节点也牵连着无法释放 , 将泄漏的内存空间迅速扩大 。
推荐阅读
- 「计算机组成原理」:一文快速了解计算机原理知识点-附思维导图
- Galaxy S21 Ultra 最新渲染图曝光,居中挖孔屏 + 后置四摄
- 暖日大视野怡梅|如今地位十分尴尬,即将退出发达国家行列,作为曾经的世界霸主
- 爱卡汽车|更强动力的宝马X8 M渲染图曝光,搭混动系统/有望2022年亮相
- 鲁大师官网|S21渲染图曝光:骁龙875+25W快充,可能不送充电器,三星Galaxy
- 天极网|三星GalaxyS21系列渲染图曝光:采用全新摄像头模组设计
- 上海市国有资产监督管理委员会网站|从产供销一体化出发,助力葡萄产业兴旺、农民增收 上海市金山区供销合作社多措推动葡萄产业高效发展
- 伊藤美诚|伊藤美诚直言想喝酒!透露来华参赛的最大原因,已经出发来中国
- 赞奇科技(渲云)携手华为云,为电影制作提供优质渲染服务
- 华为Mate40Pro|华为Mate40 Pro渲染图曝光,外观再有变化,花粉直言:辨识度很高