跨平台 UI 框架原理及展望

您所在的位置:网站首页 技术分析的主要依据是什么 跨平台 UI 框架原理及展望

跨平台 UI 框架原理及展望

2024-07-11 16:41:38| 来源: 网络整理| 查看: 265

转载请注明出处:跨平台 UI 框架原理及展望

本文在微信公众号「元创联盟」同步发布,可以扫描文章末尾二维码进行关注,获取最新文章。

文章开始之前,先约定一些技术术语

跨平台技术:提供跨平台开发工具包,可以在多种设备上(Android、iOS、PC 等设备)运行编译产物的技术,通常可以开发控制台应用程序和 GUI 应用程序 跨平台 UI 框架:用于开发 GUI 应用程序的跨平台技术,它只是跨平台技术的一个细分,下文简称「UI 框架」 跨平台 UI 渲染引擎:UI 框架中负责渲染的模块,下文简称「渲染引擎」

在讲原理之前,我们先了解 UI 框架的演进历史,先搞清楚当前 UI 框架的问题与局限性,才能做出更合适现阶段的设计。

1、UI 框架演进

UI 框架通常会有几个部分组成

内核:源码管理(打包、加载) + 渲染引擎(排版、绘制、合成、事件、动画) 生态:扩展对外开放,丰富组件,完善开发者生态 开发配套:从开发、集成、测试、发布整个研发流程的配套设施建设

概览.jpg

「内核」是 UI 框架的最核心的部分,它提供扩展能力,可以由第三方参与,提供各种组件,来完善整个开发着生态。通常来讲,开发配套则是由使用该技术的公司根据自主定制研发。

从 PC 互联网转向移动互联网的过程中,跨平台 UI 开发成为热门领域,先后涌现了较多的 UI 框架,早期以 WebView 技术的 PhoneGap、AppCan 为代表,中期以 React Native、Weex 为代表,近期以 Flutter 为代表。为什么 UI 框架会成为大前端的热门技术?一套代码,多端复用,可以节约多个端的开发成本,对公司开说确实能省下一笔不小的人力成本。按我的实际经验来看,双端复用,大致能节约 40% 左右的成本,统计方法主要是看两点:HC 和每个迭代完成需求的数量。当然随着对跨平台技术的逐步熟练,这个数据还会更高一些,还是相当可观的。其他方面则取决于市场的需求,每个阶段有不同的诉求,UI 框架解决的问题也不一样,总体概况如下

演进.jpg

1.1 第一阶段:WebView 技术为代表

重点解决的问题

开发成本:快速构建 App、多平台复用

早期 App 开始流行,市场没有足够的 Android、iOS 开发者,如何最高效、最快速搭建一个 App 是早期跨平台 UI 框架要解决的主要问题,所以 PhoneGap、AppCan 兴起。

1.2 第二阶段:React Native 为代表

重点解决的问题

开发成本:所见即所得,多平台复用 性能体验 动态化:快速迭代、热修复 包大小

随着移动互联网的发展,各个公司开始押宝移动互联网,App 开发技术的成熟,开发者数量明显增多。创业公司产品内卷严重,每个赛道都挤满了成百上千的创业公司。如此激烈的竞争下,App 的质量也逐渐变得重要,体验逐渐成为关注的焦点,各种 App 质量监控平台逐渐兴起,体验相关的数据指标也逐渐开始标准化(如 FP、FCP、FMP 等)。基于 WebView 技术开发的 App 体验明显不如 Native,所以跨平台 UI 框架也在不断向 Native 性能靠拢或者赶上,从 React Native 到 Flutter,都是在追求更极致的性能体验。

同时也衍生出动态化的需求,因为中国的公司都太焦虑了,总担心自己的产品出问题导致用户流失,所以快速迭代、快速试错、热修复成为中国公司很重要的普遍诉求,国外的公司没这种诉求,至少不是强诉求。

随着人口红利的逐渐消失,获客成本越来越高,对拉新转化率要求也比较高。包大小对于独立 App 的推广和拉新影响较大,像一些平台型 App,动则几百 M 的包大小,拉新转化率会比较低,这个时候包大小的控制反而显得尤为重要。包大小也是这个阶段的一个强诉求。

为什么是基于 Web 技术?从 PC 互联网转向移动互联网的过程中,各大公司产品也完成了从浏览器到 App 的迁移,同时 Web 技术栈也被顺理成章地移植到 App 技术栈上。其一,早期各个公司的高阶技术管理者大多都是资深的 Web 开发者(从现状来看,大前端的大佬也是 Web 出身较多),技术人员都有自己的技术喜好,把 Web 技术栈应用到 App 开发中是理所当然的事情。其二,Web 技术栈有比 App 原生技术栈的优势也比较明显

所见即所得:无需等待编译,极大提高开发效率 修改即更新:可以无需升级 App,动态更新产品功能

React Native 正是在这样的背景下出现的,将 Web 技术 React 应用到 App 开发技术栈上(Weex 亦是如此,赶时髦而已)。它在动态化和包大小控制方面有比较大的优势,性能方面一般。

我使用过 React Native 一年多时间,具体参与过很多业务开发,性能和官方宣传的有很大差距,和 Native 根本没法比。关于 React Native 的原理,可以看我的另外一篇文章:深入理解 React Native 技术原理(暂时使用飞书文档,后续再出正式文章)。性能不好的本质原因还是 JavaScript 这个弱鸡语言,但是没办法,在动态化和控制包大小方面没有比这个更廉价的方案(不是没其他方案,只是成本比较高,下面会详细说到),哪怕 Flutter 出现之后,各个公司还是想在 Flutter 上再加一层 JavaScript 的封装,号称 Web on Flutter。

1.3 第三阶段:Flutter 为代表

重点解决的问题

开发效率:所见即所得,多平台复用 性能体验:(AOT 模式)与 Native 一样的性能 多端一致性:自渲染技术,多端保持一致

React Native 并没有解决性能体验的问题,同时相比 WebView 而言,因为是用原生控件渲染,所以多端没法做到显示一致,反而是一个很坑的点,开发者依然要去做多个平台的 UI 适配工作,测试人员依然要在多个平台去做 UI 测试。Flutter 的出现解决了多端一致性的问题(其实开发时间也很长了,早期叫做 Sky Engine,现在源码里依然有 Sky 的影子),它以自渲染技术为特点,解决了了双端的不一致的问题。

在性能方面,Flutter 可以和 Native 匹敌,它和 Native 有一样精简的渲染流程,同样支持 GPU 加速,具体原理可以看我的这篇文章:Flutter 高性能渲染原理(暂时使用飞书文档,后续再出正式文章)。

但可惜的是,它不支持动态化,这也是 Web on Flutter 的重要原因。无论是什么框架,都会无端增加 App 包大小,只是框架本身带来的包大小就很大,更不用说业务代码了,Flutter 这个方面表现就很差。相比而言,React Native 可以通过动态下发 JavaScript 的方式减小安装包大小,这方面更优秀一些。Web on Flutter 的方案可以解决动态化的问题,同时相比 React Native 而言,双端一致性会更好,但是会损失性能体验。

未来的 UI 框架应该如何设计,既满足性能的诉求,也满足动态化的诉求呢?在聊这个话题之前,必须先要理解 UI 框架的技术原理。

2、UI 框架原理

UI 框架主要分为源码管理和渲染引擎两个部分。

2.1 源码管理

源码的管理可大致分为「打包」和「运行」两个阶段,打包更多是通过线下 CLI 打包工具链去完成,运行是实际执行打包后的生成文件,这两个阶段分别注重的点不一样。

打包阶段

开发期:主要解决的是「开发效率」 编辑器:所见及所得,实时预览 Hot Reload:真机调试预览,修改即生效,大大降低等待全量编译的时间 发布期:主要要解决的是「代码保护」、「包大小」、「性能」 代码 代码混淆,额外生成 mapping 文件(代码保护、包大小) tree-shaking,去除无用资源和代码(包大小) 编译优化,提高运行性能,例如 AOT 编译(性能) 资源:资源 id 数字化(便于二分查找)

运行阶段

加载:执行准备环境 代码和资源:代码同步加载到内存中,资源异步读取 环境准备:初始化必要的对象(如虚拟机、View 实例等) 执行阶段:执行入口,开始渲染流程

如果设计一个新的 UI 框架,务必要把源码管理的各个方面实现好,对使用者将会是比较友好的。动态化的支持主要看发布期如何打包源码,对应 UI 框架如何加载解析源码。在新 UI 框架的设计上可以在这个环节对「动态化」和「性能」做不同的设计和支持。

2.2 渲染引擎

渲染引擎主要的工作分为三个部分

渲染:构建 Tree、排版、绘制、合成 交互:事件 动画 2.2.1 线程模型设计

一般来说,渲染引擎可以设计为两个线程:UI 线程和 GPU 线程

UI 线程:构建 Tree、排版、绘制、事件 GPU 线程:合成

UI 线程的工作会比较多,是比较重的一个线程。事件放在 UI 线程的好处是显示和交互是一体的,不会存在事件发生的时候 UI 还有很多未完成的操作。典型的例子是 WebView,WebView 的事件处理是单独的线程,所以一个长列表,你可以无限滚动,如果 UI 线程跟不上,就会导致白屏问题,本质上还是线程设计的问题。

2.2.2 构建 Tree

界面上的每一个元素叫做一个 Node,每个 Node 都是由一个树形结构 Tree 来管理的。Tree 的生成可以有不同的方式,但最原子的操作无非是 CRUD(增、删、查、改),这个部分没什么好说的,实现 CRUD 的 API 即可。

2.2.3 排版

排版过程主要是「Measure」和「Layout」,Measure 主要是计算元素大小,得到 Size,Layout 主要是给元素定位,得到元素相对位置 Offset,或者绝对位置 Position,「位置 + 大小」确定了一个元素在屏幕上的显示区域。

这个过程中最复杂的是选择什么样的排版算法,不同的方式对于节点计算差别很大(例如 CSS 盒子模型有 static、absolute、relative 等排版方式)。不过无论是怎么排,最终只是「父决定子」还是「子决定父」两种类型,以下面的 DOM 结构进行说明

排版树.jpg

说明:蓝色是叶节点,红色是父节点,max-w / max-h 是最大值,w / h 是期望值,假设窗口大小是 800 x 600

父决定子(fixed 固定值):节点 1 [800, 600],节点 2 [100, 50],节点 3 [50, 50],节点 4 [50, 50],节点 5 [5, 5],节点 6 [50, 50] 子决定父(auto 自适应):父控件需要等所有子控件确定大小,再回溯回来确定自己大小。节点 5 [w = 800 x 20% x 10%, h = 600 x 20% x 10] = [16, 12],节点 3 由节点 4 和节点 5 共同确定,大小为 [66, 62]

上面算法中,只是计算了宽和高的情况,实际计算中还要加上盒子模型中的 margin、border、padding 的值才是正确的,而且这些值也受 max-w 和 max-h 的影响。

子决定父(auto 自适应)的这种排版方式和 Android 的 WRAP_CONTENT 意思差不多,实现方式可能不尽相同。这种方式对排版性能比较大,如果子节点大小变化,会导致父节点也变化,最坏的情况是整棵树的大小都发生变化。所以修改节点大小时刻如何进行重排?

第一种:从 Root 节点开始全部重排,性能最差的方式 第二种:从第一个确定大小的祖先节点重排(fix 方式)

第一种方式比较暴力,性能会最差,第二种比较折中,但如果整棵树都是 auto 的,那和第一种没区别。

Measure:每一个 Node 计算出了最终的大小。例如盒子模型,则得出了 margin[left, top, right, bottom],border[left, top, right, bottom],padding[left, top, right, bottom],content[width, height] 的实际大小。

Layout:根据计算出来的大小,设定 Offset 或者 Position

相对于父节点的 Offset[x, y] 相对于屏幕坐标原点的 Position[x, y]

排版过程完成,元素的「位置 + 大小」就已经确定,在屏幕上的区域也就确定了。

排版算法最高效的是 absolute 排版,全部都是「父决定子」的方式,没有回溯的过程。Flexbox 排版算法也是「父决定子」的排版算法,性能也比较好。从 React Native 的使用经验上看,基本上 Flexbox 可以满足绝大多数的业务场景,而且也是比较标准化的排版算法,是个不错的选择。自定义排版算法不建议,因为会增加很多学习成本,Android 一堆的 Layout 控件,看着就很烦,而且很多控件排版性能也很差。

2.2.4 绘制、合成

绘制(Paint)的过程就是将每个 Node 变成「图层」的过程,图层的大小是自己的 Size。这个图层并不一定是指一张内存中的 Bitmap,它只是一个虚拟概念,它可以是一些绘制操作的集合,还不一定要真正绘制到 Canvas 上。

合成(Composite),也叫光栅化,它的过程是按照图层的 z-order 排序,依次将图层绘制到同一个画布 Canvas 上,把图层合成像素。Canvas 可以是 GPU 类型 Surface 提供的,也可以是 CPU 类型的 Surface 来提供。这里主要注意两点

层级顺序:层级低的先绘制,层级高的后绘制 溢出处理:子节点是否可溢出显示

硬件加速: Canvas 只是一个虚拟画布,真正绘制的内存空间是 Surface 提供的,如果该内存空间是在 GPU 上直接分配的,那绘制效率将大大提升,它可以使用 GPU 3D 图形库直接操作(例如 OpenGL、DirectX、Metal),这些 GPU 图形库都是为 3D 游戏设计的,图形性能最好,比 CPU 模拟绘制性能会高很多。

同层渲染:这里还有个比较复杂的点是带有平台 UI 控件的合成,平台 UI 控件不一定能通过现有的 Canvas 直接绘制。例如 Android 系统,UI 控件绘制是在平台 UI 线程完成,而渲染引擎通常合成操作是在新创建的 GPU 线程去完成,这个时候要么是转到平台 UI 线程去一起合成,要么是将平台 UI 控件绘制成像素,再在 GPU 线程一起合成。这个业界的专业术语叫做「同层渲染」,意思是说平台 UI 控件与 UI 框架自带控件绘制时候也遵循 z-order 的规则,进行混合合成,这种模式会降低合成阶段性能,能不用尽量不用。

双缓冲机制:这里有个概念叫做双缓冲,它的原理就是在内存中绘制一份 copy 版,绘制好之后再一次性拷贝到真实的显示内存中,再一次性绘制到屏幕上,每一帧显示的都是完整的,而且批量操作性能也会比较高一些。

完整的流程示意图如下 渲染引擎流程.jpg

绘制和合成比较依赖图形库,比较好的选择是 Skia 这个 2D 图形库,它是跨平台的,从根本上解决了绘制的一致性的问题。经过多年的发展,它不仅支持 CPU 渲染,也支持多种 GPU 图形库的 backend,对主流 GPU 3D 图形引擎(OpenGL ES、Metal 等)都做了封装,主要是学习下 Skia 的 API 如何使用,绘制和合成这块问题就不大了。

2.2.5 事件

事件主要分为两个部分:事件抽象、事件传递。

事件抽象:DOWN(按下)、UP(抬起)、MOVE(移动)、HOVER(悬停),其他事件都可以用这些组合得到

click 事件:本质上是 DOWN 和 UP 的组合,时间间隔较短 long click 事件:本质上是 DOWN 和 UP 的组合,时间间隔较长 scroll 事件:本质上是 DOWN 和 MOVE 的组合 ...

事件传递:传递过程包括捕获和冒泡。个人认为 W3C 的事件模型是比较优秀的,捕获阶段主要是做 hit test,看事件发生点 [x,y] 是否落到控件的显示区域内,这里需要考虑 z-order,不能直接遍历 Tree。下面是 W3C 事件冒泡的示意图

事件.jpg

2.2.6 动画

动画的本质是定时触发 Node 的属性变化,属性变化再引起重排或者重绘。如果变化的属性会影响布局,则重排、重排触发重绘。如果变化的属性只影响显示,则只做重绘。动画的分类可简单分为数值动画、帧动画、自定义动画。

数值动画:设定总时间 T,动画数值 START,动画数值 END 这三个固定值,以当前时间 t 作为变化量,通过函数(一般叫做缓动函数)计算得出当前的动画数值 value。

举例:元素消耗 1s 从 A 点水平匀速移动到 B 点

总时间 T:1s,t 动画数值 START:A 点的 x 坐标 x1 动画数值 END:B 点的 x 坐标 x2 t:递增的时间,从 0 开始 缓动函数:y = ax + b 一元一次方程(x = t/T,a 和 b 都是常数,a = x2 - x1,b = x1)

Tween 有很多计算公式,能实现很多有趣的动画效果。

帧动画:是数值动画中的一种特例,设置总时间 T,总帧数,以当前时间 t 作为变化量,通过匀速函数计算得到当前帧。

动画库:无论是数值动画,帧动画还是自定义动画,均需要一个强大的动画库的支持,具体体现在

响应速度:毫秒级别的响应速度 易用性:灵活使用,例如多个动画并行、串行等 扩展性:动画状态的过程监听、如何自定义动画

这些也是设计动画的时候需要考虑的点。

2.3 总结

以上,是整个 UI 框架的核心原理,我在 5 年前写的 UI 框架就是按上述思路做的:github.com/myz7656/sma… (Windows 平台上的 UI 框架),实现一个精简版的 UI 框架并不复杂。回到现阶段主流 UI 框架存在的问题

React Native:性能差、双端不一致 Flutter:无法动态化、无法解决 App 包大小的问题

未来的 UI 框架应该如何设计去满足这些需求呢?

3、未来展望:全场景、积木式、自绘

重点解决的问题

开发成本 性能体验 多端一致性 动态化 包大小

演进_未来.jpg

动态化和性能体验是一个矛盾点,动态化必定会牺牲部分性能体验,一个 App 并非所有业务都需要动态化,一个好的 UI 框架应该能解决所有场景的诉求,例如 App 首页的强诉求是

首次有效绘制时长:即 FMP 指标(首屏可见元素增幅趋于稳定的时刻)是否能做到秒级别 首次可交互时间:即 TTI 指标(屏幕元素多久能响应有效点击)

这种场景下显然不适合重量级 UI 框架的加载,像 WebView、Flutter 等框架从加载到 GPU 绘制出第一帧就消耗了几百 ms,根本不可能优化。

而一些活动页面,PV 较小的页面,它本身不应该过多占用 App 的包大小,这种可以牺牲部分体验,通过动态化的方式去加载。

无论是 WebView、React Native 还是 Flutter,以上基于「虚拟机」的 UI 框架都太过于大包大揽了,结果就是

启动慢 占用内存高

下面是一个 FMP 指标的大致对比 启动时间说明.jpg

Native:只有解析 XML、排版、渲染的流程 React Native:由于 JavaScript 这个弱鸡,即使引擎缓存,也做不到那么高性能,具体可以看上面的原理文章 Flutter:在引擎缓存的情况下,基本可以做到和 Native 一样的页面加载性能,具体可以看上面的原理文章 Web on Flutter 就更是一个灾难了,两个虚拟机,高内存消耗。都预热的情况下,与 React Native 相比 性能:差不多,谁比谁好,关键看内部设计实现细节 多端一致性:更优(得益于 Skia) 平台支持数量:更多(得益于 Skia)

本质上,Web on Flutter 的方案弥补了 React Native 多端数量、一致性的问题,带来的是及其复杂的架构设计,对于稳定性和质量的技术挑战比较高,占用系统资源也更多(CPU、内存)。

一般来说,在存量业务中,UI 框架只能以「add to app」的形式应用到业务开发中。在公司的产品都已经成熟的情况下,一个新的框架出现很难做到 100% 普及,业务存量代码也不可能 100% 迁移到新框架上,作为后来者,只是一个辅助选项,所以这些问题就成了必须解决的问题,不解决的话出现的问题就是「看上去性能差」。启动慢可以通过预热、引擎缓存等方式解决,但是这会额外消耗资源(CPU、内存),一个平台型 App 中,资源本身就很有限,你抢占了线程,别的业务就得等待,始终不是一个完美的解决办法。像阿里文章中所说,一个 App 中存在 3 个左右容器,如果每个容器都预热,那是多大的内存开销。主要看如何抉择,是以时间换空间,还是以空间换时间,鱼和熊掌不可兼得。

所以要满足全场景的支持,必须提炼 UI 框架做成模块化可拆分组合的,将源码管理(编译、加载)和渲染引擎分开,两段式设计,渲染引擎只关注核心(排版、渲染),不同的场景可以搭积木式地自由组合

高性能场景:渲染引擎 +(模版) 动态化场景:渲染引擎 +(虚拟机 + 动态语言)

如何设计呢?Web 技术是非常成熟且非常值得学习的,它除了性能差点,其他一切都是优点,而且可以做到上面的一切目标。WebView 本身性能差的原因还是在于带着 W3C 的历史包袱

启动性能:本身容器很重,需要初始化的东西比较多,例如 JavaScriptCore / V8 的虚拟机环境 渲染性能:它有比较复杂的渲染流程和线程模型,当然这个官方也一直在优化。不过因为要兼容 W3C 所有标准,导致渲染的时候要走很多无关紧要的步骤,例如 flex-shrink 有可能会走两次排版的流程

WebView 更深入了解可以看这篇文章:从 Blink 内核渲染架构演进看浏览器技术发展。国内很多浏览器厂商号称自己比 Chrome 快多少快多少,是真的谷歌工程师水平不如国内吗?非也,优化方式只有一种:甩掉旧包袱,干掉拖累性能的标准,这是唯一的出路(个人比较欣赏苹果的做法,不留技术包袱)。W3C 的标准又臭又长,在日常开发中,其实也用不到多少,Flutter 估计就是看不下去了才另起炉灶。

相比另起炉灶,我更倾向于用旧标准去做裁剪,可以实现 W3C 标准中比较常用的「子集」。原因嘛自然是「车同轨,书同文,行同伦」,既然叫大前端,那就应该统一标准,而不是开发新标准

统一认知:降低学习成本,降低沟通交流的成本 便于迁移和适配:与大前端各种轮子互通,无论前端有多少轮子,最终到浏览器也只有两种形态 CSR:客户端渲染模式,通过执行 JavaScript 调用 DOM API 在客户端生成页面 SSR:服务端渲染模式,通过服务端生成 HTML、CSS 下发,WebCore 解析生成页面

无论是哪种形态,以 W3C 标准「子集」去设计,都能比较方便地适配,以不变应万变,在前端轮子层出不穷的今天,这才是上上之选。同时,保留精简的子集规范,设计和 Native 一样的渲染流程,必定可以做到高性能。

我们可以把 WebView 拆成两个部分:WebCore 和 JavaScriptCore 来看,重点做好「W3C 标准子集」与「排版渲染引擎」即可。

设计思路.jpg

这个与 Rax 最近开源的项目思路比较一致,但是并不是我抄袭了这个思路,我在 5 年前写的 UI 框架就是按这个思路做的:github.com/myz7656/sma…

我实现了

CSS 样式:42 个,标准 + 部分自定义 HTML 控件:(标准)div、span、br;(自定义)list、panel、button、img、realwnd

list 是用来做高性能列表的,支持和 RecycleView 一样的复用机制,button 支持类似 Android 的 .9 图,realwnd 是用来承载系统控件的,和 Flutter 的 PlatformView 一样的功能。(我实在是太懒了,不喜欢写文档,后面有时间再补补)。

所以根据上面的设计思路再细化一点

高性能场景(轻量级 WebCore):渲染引擎 +(模版) HTML + CSS XML + CSS 其他 DSL 组合 动态化场景(轻量级 WebView):渲染引擎 +(虚拟机 + 动态语言) Lua 引擎 + Lua 语言 V8 / JSC 引擎 + JavaScript(大前端最爱,肯定选这套组合) 自研虚拟机 + 语言

整体架构设计(两段式架构) 架构图.jpg

渲染引擎通过 DOM API 的提供调用,在高性能场景,可以实现一个「轻量级 WebCore」,动态化场景基本可以看作是实现一个「轻量级 WebView」。

这将会是我以后业余时间长期投入的个人项目,继续把 smart-ui 发扬光大(看完 Flutter 源码之后,再看 smart-ui,还是太嫩了)。

4、补充说明 4.1 性能与动态化的矛盾

本质上来说,动态化与性能是没法同时满足的。极致的性能需要编译成二进制可执行文件,而 Android、iOS 系统是禁止二进制可执行文件下发的。所以能动态下发的,可以是

中间码:在目标平台上通过虚拟机解释执行 源代码:在目标平台上通过虚拟机先编译成中间码,再解释执行

Flutter 可以动态下发中间码(对框架进行改造),Dart VM 加载中间码解释执行。而通常对接 Web 技术的动态化方案采用下发 JavaScript 源代码,V8 / JavaScriptCore 通过编译源代码的方式执行。无论哪种方式,性能都并不会很好。那是否可以像 Android Dalvik 虚拟机一样的 AOT 机制,下发中间码,在目标平台编译成二进制码呢?V8 引擎在编译的时候可选择是否带 JIT 编译器,JIT 编译器的作用就是将「热点中间码」编译成二进制码执行,以提高性能。

V8 执行过程 JIT.jpg

既然 Flutter 可以在编译的时候可以编译成二进制,理论上可以通过改造 Dart VM,将 AOT 编译器集成到 UI 框架中,将下发的中间码编译成二进制码,个人认为这条路也是走得通的,不过成本比较高,而且带上 AOT 编译器,整个 UI 框架的包大小估计会增大不少(不过这块没太做较深入的了解,也可能因为我理解有限,这条路走不通)。

4.2 AOT 与 JIT

一般来说,编译器包括三个部分

前端:用于分析各种语言的源代码语法,形成语法树,用于生成中间码(如 Java 字节码、LLVM 中间码等) 优化器:对中间码进行优化,使代码更高效 后端:将中间码编译成目标平台的二进制指令(Arm、Armv8、x86、x64 等)

LLVM、GCC 都是按这种方式设计的,三段式编译器的优点在于

前端:接受一切语言规则,只要可以生成编译器中间码即可,常见的中间码包括 LLVM IR,Java 字节码 后端:可以生成基于任何 CPU 指令集的二进制码

大多虚拟机也是按这个方式去设计的,比较优秀的是 Java 虚拟机,只要基于 Java 虚拟机字节码规范,任何语言生成的字节码都可以被虚拟机接受并执行。虚拟机包括编译器后端吗?大多虚拟机是加载中间码解释执行的,核心是「解释器」,但是为了提高性能,一般都会配备「JIT 编译器」(这里指编译器后端),对热点中间码进行编译,生成二进制码,下次运行直接运行二进制码。V8 虚拟机和 Dart 虚拟机本质也一样。

AOT 和 JIT 的区别在于使用编译器的时机

AOT:Ahead Of Time,运行之前已经将所有中间码编译成二进制码 JIT:Just In Time,在运行时刻监控热点代码,将热点代码编译成二进制码

AOT 能极大提高程序的运行性能,JIT 只能有限地提高性能。Android Dalvik 虚拟机也提供了 AOT 的能力,在 App 安装的时候进行编译,所以安装时间明显变长。

JIT 在手机端能提升多少性能,个人觉得并不会很理想,对热点代码的追踪,达到一定运行次数方可生效,App 运行多少次才能达到这个次数呢,不好说。即使可以设置这个次数,设置多少合适,也是一个不太好选择的点。静态语言,一个函数可以直接对标到一段汇编,再对标一段二进制,因为分配多少内存,地址是多少是明确的。而 JavaScript 本身是动态语言,它可能的情况是,一个函数

A 参数 A 汇编码 A 二进制码

B 参数 B 汇编码 B 二进制码

JIT 如果次数过低,不同的参数生成的二进制文件就会很多很大。相比而言,服务端的 JIT 性能更加有意义。对于静态类型语言而言,客户端 AOT 是最好的选择。

qrcode_for_gh_0dbe4d91e56e_258.jpg



【本文地址】

公司简介

联系我们

今日新闻


点击排行

实验室常用的仪器、试剂和
说到实验室常用到的东西,主要就分为仪器、试剂和耗
不用再找了,全球10大实验
01、赛默飞世尔科技(热电)Thermo Fisher Scientif
三代水柜的量产巅峰T-72坦
作者:寞寒最近,西边闹腾挺大,本来小寞以为忙完这
通风柜跟实验室通风系统有
说到通风柜跟实验室通风,不少人都纠结二者到底是不
集消毒杀菌、烘干收纳为一
厨房是家里细菌较多的地方,潮湿的环境、没有完全密
实验室设备之全钢实验台如
全钢实验台是实验室家具中较为重要的家具之一,很多

推荐新闻


图片新闻

实验室药品柜的特性有哪些
实验室药品柜是实验室家具的重要组成部分之一,主要
小学科学实验中有哪些教学
计算机 计算器 一般 打孔器 打气筒 仪器车 显微镜
实验室各种仪器原理动图讲
1.紫外分光光谱UV分析原理:吸收紫外光能量,引起分
高中化学常见仪器及实验装
1、可加热仪器:2、计量仪器:(1)仪器A的名称:量
微生物操作主要设备和器具
今天盘点一下微生物操作主要设备和器具,别嫌我啰嗦
浅谈通风柜使用基本常识
 众所周知,通风柜功能中最主要的就是排气功能。在

专题文章

    CopyRight 2018-2019 实验室设备网 版权所有 win10的实时保护怎么永久关闭