Hummer是UC内核团队定制的Flutter引擎,它基于官方Flutter引擎进行优化增强,经过近两年的研究,我们对Flutter技术的原理及优劣势有了更加深入的认识。在这里,我们计划通过这个公众号,向大家分享我们对Flutter的理解和优化,希望能通过剖析引擎实现原理,让大家对Flutter的优劣有一个更客观准确的认识。
接下来,我们将陆续推送Hummer引擎优化系列文章,敬请期待。这里先做一下整体的介绍。
优化介绍
性能优化
在开始进军Flutter引擎的头一年,我们的性能优化思路,更多的是从纯引擎层面进行整体的优化,例如初始化速度的优化、渲染管线优化、vsync调度优化等,经过这一年的优化,Hummer的性能相对于原生Flutter已经有比较明显的提升,部分的优化点我们也以PR的形式回到官方主线,得到认同。
首先是针对初始化性能的优化,这个我们之前已经发表过两篇文章《Hummer 引擎优化系列 - 如何提升 5 倍 Flutter 启动性能》和《Hummer 引擎优化系列 - 如何提升 Flutter 首帧性能》,对Hummer的启动和首帧优化做了一个比较详细的分析和介绍。
接着在渲染管线和流畅度方面的优化,我们在对比分析了Flutter和其他技术(Web和Native)的渲染差异,以及应用层面的优化和局限性之后,通过sliver分帧处理、引入高延迟渲染调度、Android线程优先级调整等手段进行优化之后,使得UC某业务在主流低端机上有20%-50%的提升,个别场景下甚至略优于native版本。
随着官方的演进及Hummer的一系列优化上线,我们也开始不局限于从纯引擎层面去优化性能,而是更加关注实际的业务效果,结合实际业务体验来推动引擎优化演进。所以今年我们从具体的业务场景出发,结合一些典型的场景进行性能优化。总的来说,目前有3类场景,Flutter的性能仍面临着比较大的挑战:
冷启、复杂页面的首屏性能。对于简单的页面,业务经过简单的调优,基本上都能达到闪开的效果,但是对于比较复杂的页面,或者是有很多网络资源需要加载的页面,它的首屏往往很难达到比较理想的效果,特别是在冷启的时候。
复杂长列表的滚动性能。去年Hummer已经针对长列表滚动做了一系列的优化,包括高延迟渲染管线、Sliver多节点分帧、单节点分帧等,基本上已经可以满足大部分场景的性能诉求。但是在一些比较极端的场景,例如用Flutter开发的本地相册页面,在图片非常多的情况下(上万张),如果进行快速的远距离拖动,这时候因为原本的Sliver排版机制的限制,它需要依次解码非常多的图片节点,仍然会造成巨大的卡顿。
TextureView作为RenderSurface。原生Flutter提供了SurfaceView和TextureView 两种机制作为Engine的RenderSurface,虽然SurfaceView的渲染链路更短、性能明显更好,但是由于它独立合成的架构特点,会出现一些View层次结构不对、动画过程闪黑等问题,很多业务不得不使用较低性能并且存在各种瑕疵弊端的TextureView作为RenderSurface,或者使用截图过渡方案。
针对第一个场景,Hummer提供了基于单Engine的预渲染机制,用最小的内存开销实现预渲染,并保持了开发模式的一致性。这里包括了3种场景预渲染:
前台是Native页面,预渲染Flutter页面;
前台是Flutter页面,预渲染另一个Flutter页面;
PageView后台页面预创建。
最终,结合Hummer提供的这些机制和能力,复杂的业务页面在低端机上的冷启也实现了闪开的效果。
针对第二个场景,Hummer提供了一种高效的Sliver列表组件,它主要是参考SliverFixedExtentList的实现机制,但是提供了更灵活宽泛的使用方式,将列表节点与viewport偏移的对应关系的控制逻辑上升到应用层,使得业务可以根据各自不同的列表节点高度规则,来适应更复杂多变的业务场景。得益于引擎和业务这种各司其职互相配合的设计,在夸克的相册页面,即使数万张图片级别的长列表,在低端机上也可以流畅的随意的远距离滚动。留意到社区里大家都在吐槽Flutter在处理长列表的远距离滑动的卡顿问题,目前这套方案我们也在积极的PR(https://github.com/flutter/flutter/pull/100117)回官方主线中。
针对第三个场景,Hummer提供了2套解决方案:
提供了FlutterImageView作为Flutter的RenderSurface,它的性能虽然没有SurfaceView好,但是解决了TextureView的吞帧问题、特殊机型高刷适配问题,作为TextureView的一种更好的替代方案。
提供了引擎层面的SurfaceView动态切换方案,业务通过非常简单的API接入,就能让页面在主场景使用SurfaceView作为RenderSurface,保证良好的性能,并且在动画过渡场景由引擎自动进行TextureView的切换,以保证效果。
除了解决问题,如何准确有效地发现和分析问题也非常重要,今年我们在线上监控这块也发力共建,结合引擎侧的能力,对流畅度指标进行了彻底的重构和优化,使得线上流畅度指标与用户体验更加贴近,更有利于问题的发现和效果评估,并且尝试在卡顿时上传trace信息,以提供一定的分析定位能力。
性能优化作为移动端经久不衰的话题,Hummer仍然在不断深入探索,接下来我们会继续从具体的业务场景出发,提供接地气的解决方案,让业务可以更轻松开发出高性能的Flutter页面,达到媲美Native的性能体验。
包size优化
随着人口红利的消失,下沉市场成为用增的一个重要战场,而下沉市场用户对包size的敏感度要远高于一二线城市用户。Flutter作为一个新引入的技术,它带来的size增量尤其受到关注,部分app甚至会因为包size限制而放弃Flutter技术,或者在Android端使用全量动态下发的方式,牺牲了一定的用户体验。所以如何减少Flutter技术带来的size增量,是一个非常重要的命题。
今年我们从引擎产物、业务产物、资源各个维度进行梳理,通过 模块裁剪、符号裁剪、优化编译产物、资源精简等手段,将Flutter业务的size平均降低了30%左右。
从长远角度来讲,引擎功能裁剪的空间已经非常小,而代码产物及资源的优化难度会越来越大,最终将会达到一个天花板,对于有极致size要求的业务来说,最终还是要走向动态下发的道路。动态化会面临3个问题:
如何做到双端一致,特别是iOS如何实现?
如何减少性能损耗,包括包下载导致的首屏性能折损、运行时代码性能折损?
如何做到比较一致的开发体验及广泛的场景支持?
目前Android上面有些团队会使用整包下发的方案,而官方在2.x版本提供了Deferred Compontents机制进行业务代码的分包下发,由于原生Deferred Components机制需要配合Google Play Store相关机制进行使用,Hummer对它进行了“本土化”,以适应自己的下发平台。
包下发的机制,目前最大的缺陷是它无法适配iOS平台,使得它的实用性大打折扣,所以我们一直致力于探索Flutter上面的终极动态化方案,历时近2年的开发与优化,目前已经取得非常不错的效果。
内存稳定性
稳定性一直是app关注的核心指标之一,UC内核团队在稳定性优化方面有着比较深厚的积累,如今我们也把相关经验应用到Hummer上面,提升整个引擎的稳定性。
内存问题是Flutter稳定性的重点,而Flutter引擎自身兼容性或者逻辑bug的情况并不严重,对比Native只有其1/4的水平。Hummer引擎在近一年投入中,成功治理了内存和稳定性问题,使得Hummer在与Native对比中获得决定性优势,为业务顺利从Native过渡到Hummer奠定了坚实基础。
Dart优化
众所周知,Flutter使用Dart作为它的主要编程语言,业务逻辑以及Framework都是使用Dart实现,包size的主要增量也是来源于dart代码产物,提升Dart代码的运行性能以及降低产物size,对Flutter应用来说有非常重要的意义。
我们在引入了LLVM作为Dart AOT产物的编译后端,有效提升了Dart代码的性能30%+,产物size压缩前降低8-15%,压缩后降低3-5%。今年Hummer Dart团队继续在代码优化方面深入挖掘,通过对LLVM编译后端的深入优化,进一步降低了dart产物size,并且引入了并行编译机制,解决了LLVM编译优化耗时过长的问题,提升业务构建速度。
主要的优化点及收益如下面表格所示(由于该部分优化效果跟具体业务、机型关联度较高,所以这里主要是基于UC和夸克Flutter业务做一个粗略的统计供参考):
优化点 | 收益 |
LTO | 首屏性能:幽默段子在不同机型上优化4-8%,个人中心优化6-9% 包size优化:UC 32/64 位压缩后分别下降约3%和7%,夸克分别下降约6%和10% |
并行编译 | 编译效率提升:UC 编译耗时缩短37%,夸克缩短50% |
BoxInt64消除 | 包size优化:夸克压缩前降低 1-2%,压缩后大约降低 0.5-1% |
内存写屏障 | 包size优化:夸克压缩前降低约4%,压缩后降低约3% |
constant 优化 | 包size优化:夸克压缩前降低约0.5% |
寄存器传参优化 + CSR | 包size优化:夸克32/64位压缩前分别降低约5%和6%, 压缩后分别降低0.3%和4% |
除了优化Dart产物性能,我们也发现和解决了dart虚拟机的一些疑难问题,进一步提升了Flutter应用的稳定性。
功能增强
除了性能方面的优化,Hummer也做了部分能力的增强,包括:
自适应 DarkMode方案
网络库增强方案
混合渲染优化
图片解码深度优化
PlatformView优化
总结
以上,我们大致罗列了Hummer在引擎层面,以及结合业务实践所做的一系列优化,让大家对Hummer有一个整体上的认知。后续,我们将陆续推送一系列文章,对其中的一些核心技术点展开详细介绍,敬请期待。
经历了几年的发展,如今Flutter在移动端已经逐渐走向成熟,大家对它的认识与预期也逐渐走向理智,从部分业务团队的深入应用上看,它的价值已经被充分证实:在提供接近Native的体验同时,有效地提升了业务开发效率,也缓解了双端不平衡的人力压力。
经过新的一年发展,虽然Flutter技术更加成熟,但是我们对它的仍然保持着与去年相同的理解——“Flutter主要用于取代部分Native业务场景的开发,提高Native业务的开发效率及体验”,目前在一些复杂场景下面,Flutter仍然有着一些挑战,整个技术生态也需要更多的时间来发展完善,各种基础设施对比起native端的积累还有一定距离。
接下来Flutter的发展方向,其实官方在2022 roadmap已经写得比较清晰,主要是完善开发者体验(包括开发调试、组件生态等)、完善各种场景的性能体验,以及各桌面平台、Web端的适配。前面2点跟Hummer团队的规划不谋而合,而桌面平台、Web端这块目前我们更倾向于跟进官方的进展。
结尾
UC 内核团队,专注渲染引擎 & 虚拟机技术十数年。作为阿里巴巴集团经济体共建 Flutter 的重要参与方,积极拥抱社区,力求给业务带来最大化的价值提升。Hummer 是我们深度定制优化的 Flutter 引擎,融合了团队在 Web 引擎上的多年技术沉淀。欢迎从事相关技术研究或基于 Flutter 构建应用的同学提出宝贵的意见或建议。
U4内核致力于打造性能最好、最安全的web平台,让web无所不能;
Hummer引擎旨在全面对标native性能,提升native业务开发效率及体验。
关注请长按二维码
喜欢请分享到朋友圈
春季2023届校园热招进行中,点击文末“阅读原文”了解更多信息。