Flutter 高性能原理浅析

Flutter 高性能原理浅析

[图片上传失败...(image-1a480b-1642738386010)]

北斗星_And关注

1<time datetime="2019-07-29T01:34:03.000Z" style="box-sizing: border-box; margin-right: 10px;">2019.07.29 09:34:03</time>字数 2,470阅读 4,273

<article class="_2rhmJa" style="box-sizing: border-box; display: block; font-weight: 400; line-height: 1.8; margin-bottom: 20px; word-break: break-word; position: relative;">

这是我第三篇Flutter相关博客
欢迎 查看我的前两篇 Flutter实现篇

前言

Flutter是Google用以帮助开发者在Ios和Android两个平台开发高质量原生应用的全新移动UI框架.我开始认识Flutter时,经历了三个Flutter重要历史版本.

  • 2018年2月27日,在2018世界移动大会上,Google发布了Flutter的第一个Beta版本。
  • 2018年6月21日,在全球大前端技术大会上,发布了第一个Release Perview 1版本。
  • 2018年12月5日第一个Release 1.0版本发布.

此后越来越多的人开始关注到Flutter。

在 Flutter 诞生之前,已经有许多跨平台 UI 框架的方案,比如基于 WebView 的 Cordova、AppCan 等,还有使用 HTML+JavaScript 渲染成原生控件的 React Native、Weex 等。Flutter 则开辟了一种全新的思路,从头到 尾重写一套跨平台的 UI 框架,包括 UI 控件、渲染逻辑甚至开发语言。

Flutter框架

image

从图中可以看出 Flutter主要被分为两层 Framework层和Flutter Engine.

Framework层全部使用Dart编写,有完整UI框架的API,并预写了Android(MaterialDesign)和IOS的(Cupertino)风格的UI,极大方便了开发移动端.

Framework 底层是 Flutter 引擎, 引擎主要负责图形绘制 (Skia)、 文字排版 (libtxt) 和提供 Dart 运行时, 引擎全部使用 C++实现.

Flutter高性能原理

与其他跨平台框架对比

在看Flutter框架前,我们先看一下其他跨平台框架的设计

image

看Hybrid的架构,我们可以知道UI层的渲染是基于Webview去渲染,他的性能取决于webview的渲染性能,目前已知webview渲染性能 < NativeUI的性能

image

RN/Weex 的架构中,是基于Native的UI框架去适配,中间多了一层js转NativeUI的过程

image

而Flutter不需要中间层(Webview,js 转NativeUI这个过程),他是基于图像渲染引擎去直接绘制UI.

Dart 对于UI框架的高性能支持

我们知道Flutter的Framework层是使用了Dart语言编写,那Dart语言有哪些优势呢?下面分为几个点来阐述

Dart内存分配机制

DartVM的内存分配策略非常简单,创建对象时只需要在现有堆上移动指针,内存增长始终是线形的,省去了查找可用内存段的过程

image

Dart中类似线程的概念叫做Isolate,每个Isolate之间是无法共享内存的,所以这种分配策略可以让Dart实现无锁的快速分配。

Dart 垃圾回收机制

Dart的垃圾回收也采用了多生代算法,新生代在回收内存时采用了“半空间”算法,触发垃圾回收时Dart会将当前半空间中的“活跃”对象拷贝到备用空间,然后整体释放当前空间的所有内存如图.

image

整个过程中Dart只需要操作少量的“活跃”对象,大量的没有引用的“死亡”对象则被忽略,这种 多生代无锁垃圾回收器,专门为UI框架中常见的大量Widgets对象创建和销毁优化,非常适合Flutter框架中大量Widget重建的场景.

Dart 编体积优化,及编译JIT和AOT支持

代码体积优化(Tree Shaking),编译时只保留运行时需要调用的代码(不允许反射这样的隐式引用),所以庞大的Widgets库不会造成发布体积过大。

Dart支持两种编译模式:

  • JIT编译 Just In Time Compiler -即时编译
  • AOT编译Ahead Of Time 预编译

在debug模式下使用JIT编译,生成srcipt/bytecode进行解释执行,可以支持HotReload(热重载),修改代码,保持即可在设备上看到效果. 而在Release下 AOT编译生成Machine Code,高效的运行.

Dart 单线程 异步消息机制

客户端交互简述

对于移动端的交互来说,大多数情况下都是在等待状态,等待网络请求,等待用户输入等.那么设想一下,发起一个网络请求只在一个线程中可以进行吗?当然网络请求肯定是异步的(注意这里说的异步而多线程并非一个概念.),事实验证是可以的,Flutter就采用了Dart这种单线程机制,省去了多线程上下文切换带来的性能损耗.(对于高耗时操作,也同样支持多线程操作,通过Isolate开启,不过注意这里的多线程,内存是无法共享的.)

Dart 异步消息原理

当一个Dart的方法开始执行时,他会一直执行直至达到这个方法的退出点。换句话说Dart的方法是不会被其他Dart代码打断的。
当一个Dart应用开始的标志是它的main isolate执行了main方法。当main方法退出后,main isolate的线程就会去逐一处理消息队列中的消息。

image

有了消息队列,然后有了循环去读取消息队列中的消息,就可以有单线程去执行异步消息的能力.
一般的消息使用dart:async中使用Future来支持异步消息.

Flutter Engine 高性能

在讲Flutter Engin层时,我们先讲一下屏幕绘制的原理.

屏幕绘制原理

image

我们都知道显示器以固定的频率刷新,比如 iPhone的 60Hz、iPad Pro的 120Hz。当一帧图像绘制完毕后准备绘制下一帧时,显示器会发出一个垂直同步信号(VSync),所以 60Hz的屏幕就会一秒内发出 60次这样的信号。

并且一般地来说,计算机系统中,CPU、GPU和显示器以一种特定的方式协作:CPU将计算好的显示内容提交给 GPU,GPU渲染后放入帧缓冲区,然后视频控制器按照 VSync信号从帧缓冲区取帧数据传递给显示器显示。

作为一个专职Android开发,看过Android的绘图机制,通过SurfaceFlinger 和HAL层之间的工作机制发现和Flutter的很像,那么IOS的如何呢?个人推测屏幕的绘图机制是一样的,只是不同平台有不同实现.

Flutter Engine的渲染机制

image

Flutter只关心向 GPU提供视图数据,GPU的 VSync信号同步到 UI线程,UI线程使用 Dart来构建抽象的视图结构,这份数据结构在 GPU线程进行图层合成,视图数据提供给 Skia引擎渲染为 GPU数据,这些数据通过 OpenGL或者 Vulkan提供给 GPU.

所以 Flutter并不关心显示器、视频控制器以及 GPU具体工作,它只关心 GPU发出的 VSync信号,尽可能快地在两个 VSync信号之间计算并合成视图数据,并且把数据提供给 GPU.

Flutter Framework层的绘图机制

UI树原理

image

在 Flutter 界面渲染过程分为 3 个阶段: 布局、绘制、合成.

而布局阶段,有三个重要的对象.RenderObject、Element、Widget.

image
  • Widget是开发经常接触的控件,默认是只读的.

  • Element 是 Flutter 用来分离控件树和真正的渲染 对象的中间层, 控件用来描述对应的 element 属性,控件重建后可能会复用同一个 element.

  • RenderObject 负责提供配置信息并创建具体的 Element。

Element 持有真正负责布局、 绘制和碰撞测试 (hit test) 的 RenderObject 对象.

那么这样,如果控件的属性发生了变化 (因为控件的属性是只 读的, 所以变化也就意味着重新创建了新的控件树), 但是其树上每个节点的类型没有变化时, element 树和 render 树可以完全重用原来的对象 (因为 element 和 render object 的属性都是可变的)

布局原理

传统布局,如Android可能需要多次Measure,计算宽高。Flutter 采用约束进行单次测量布局. 整个布局过程中只需要深度遍历一次,极大的提升效能。

image

渲染对象树中的每个对象都会在布局过程中接受父 对象的 Constraints 参数,决定自己的大小, 然后父对象 就可以按照自己的逻辑决定各个子对象的位置,完成布局过程.

子对象不存储自己在容器中的位置, 所以在它的位置发生改变时并不需要重新布局或者绘制. 子对象的位 置信息存储在它自己的 parentData 字段中,但是该字段由它的父对象负责维护,自身并不关心该字段的内容。

同时也因为这种简单的布局逻辑, Flutter 可以在某些节 点设置布局边界 (Relayout boundary), 即当边界内的任 何对象发生重新布局时, 不会影响边界外的对象, 反之亦然.

</article>

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 203,547评论 6 477
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,399评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 150,428评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,599评论 1 274
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,612评论 5 365
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,577评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 37,941评论 3 395
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,603评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,852评论 1 297
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,605评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,693评论 1 329
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,375评论 4 318
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,955评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,936评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,172评论 1 259
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 43,970评论 2 349
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,414评论 2 342

推荐阅读更多精彩内容