在先前的系列文章中,我们已经介绍了 Android 10 的许多改进:深色主题背景、手势导航、隐私加强……

但对我来说,Android 10 中最令人激动的改进其实是底层 ART 的再次性能优化,相比 Android 9,Android 10 的应用冷启动更快,运行也更为顺畅,理论上来说,消耗的内存也更少。

一倍速下冷启动桌面上的应用

这是怎么做到的?我们得从 Android 应用的「编译」说起。

「编译」究竟是什么?

我们都知道,ART 从 Android 5.0 Lollipop 开始正式取代 Dalvik 成为 Android 系统的默认运行时环境,Android 的流畅度也正是从那时开始有了质的飞跃。

运行时环境的改变为什么会带来这样的变化?

正如我们在介绍 EMUI 方舟编译器 时所介绍的那样,要运行 Android 应用,系统需要将应用的编程语言转换成 CPU 能够读懂的机器码,这种将应用的编程语言转换为机器码的过程就是「编译」

而早期的 Android 系统大多都采用「解释执行」和 JIT(Just in time)的方法来进行编译,在应用运行的同时编译机器代码,虽然对内存和存储空间的压力相对较小,但应用运行的效率也因此变得低下,应用卡顿、无响应都是常事。

JIT 编译示意图

在 ART 运行时环境启用后,Google 开始采用一种名为预先编译(AOT, Ahead Of Time)的方法,在应用安装时便一股脑儿将代码都编译为手机能够读得懂的 odex 格式代码。

这种做法避开了解释执行和 JIT「同传」带来的运行效率问题,但安装和更新应用耗费的性能和时间都相应变长,一次安装甚至可能需要等待几十秒的时间。另外,这种完全编译的方式还会使得应用占用更大的存储空间。

早期 Android 这个界面非常常见……

举个形象的例子,这种做法就好比厨师把菜单上的所有菜都做完后,再一并端给顾客,顾客虽吃得开心畅快,可这一桌子的菜可让他们等得太久了。

考虑到实际的用户体验,Google 从 Android 7.0 开始做出让步,尝试结合使用预先编译和即时编译两种方法,让应用在安装时间、所占空间和运行性能之间达到一个平衡。

编译方式对比示意

怎样的「编译」方式最合适?

如果要在预先编译和即时编译之间选择一个平衡点,那应用内哪些代码应该预先编译,哪些代码可以暂时不做编译呢?

当然是你我(也就是用户)说了算

具体而言,Google 希望让系统生成一套配置文件来引导并优化这个编译过程。以 Pixel 为例,最初安装应用的时系统不会进行任何预先编译,以最快的速度完成应用安装。而在应用前几次运行时,系统就会对其进行即时编译,同时还会生成对应的配置文件。随后,手机在闲置、充电时,手机系统的编译器(dex2oat)就会根据这个配置文件对用户日常使用中常用到的部分代码进行预先编译。

从 Android N 开始后由配置文件来引导应用编译,使得应用的启动速度随着使用时间越来越快。
来源:Google 内部数据。
这样一来,用户使用时间越长,手机上的应用被编译的部分就越多,应用的启动速度就会越来越快。在不影响应用启动性能的同时,还能减少应用所占用的内存和存储空间。

同样用上面提到的那位「厨师」做例子:这种编译方式就好像一位聪明的厨师,他在顾客下单时多问了一句顾客的喜好,然后先呈上了顾客喜欢的菜,让顾客边吃边等。

说到这里可能有人会问了:

有没有办法,可以让顾客在到店前先用小程序远程点单,预先声明自己爱吃什么菜,让厨师上菜更快一些?

这就是 Android 10 带来的改进——通过 Google Play Cloud 下发 ART 优化配置文件,从而提高应用的启动性能。具体而言:

  1. 汇总用户提交的匿名配置文件,在云中对这些数据进行分析,为每一款应用生成一个高效、稳定的代码编译配置文件。
  2. 利用 Android 9 中引入的新类型文件,将此编译配置文件通过 Google Play 应用商店随应用下发给用户。
  3. 在安装时根据配置文件对将会被高频使用那部分代码进行提前编译,使得应用在被用户初次启动时就一定获得一定的优化。
汇总多台设备的匿名数据,在云端生成核心配置,并通过 Play 商店随应用安装下发给新的设备。

实际的优化过程、具体步骤、实际优势肯定要更为复杂。通过这三个步骤,无需开发者劳心,Google 已经于去年年底开始向 Play Store 上的所有应用下发云端生成的配置文件。这使得:

  • 超过 30000 个应用的性能得到改进;
  • 应用的平均冷启动速度加快了 15%,部分应用甚至能够加快 20% ~ 30%;
  • 应用的安装耗时几乎没有增加;
  • 所有搭载 Android 9、Android 10 的设备均能从中受益。
从云端下发编译配置文件后,部分应用的启动速度加快数据。

Google 也在这篇博文中表示这样利用配置文件聚合匿名的用户数据进行分析,最后回馈改善用户体验的模式可以应用到更多的领域。比如让开发者根据这些数据中应用代码与用户的相关性、重要性来重新衡量、精简、组织应用中的代码,使得应用更高效。搭配 App Bundle 特性,现在开发者已经可以将应用拆分分发,缩小应用体积。

来自用户,回馈用户,这就是生态。

自己动手完成应用编译

如果你的设备还停留在 Android 7、Android 8,并不支持前文所述的新特性,如果你并不能顺畅地连上 Play Store,设备的厂商也没有做针对性的编译优化,如果你对应用的启动速度并不满意,也乐意用存储空间来换取一些速度,都可以通过 adb 自己动手下达完全编译应用的指令。

通过手机连接到电脑后执行 adb shell,或是在手机上直接打开终端模拟器:

强制编译某个软件包

cmd package compile -m speed -f com.tencent.mm #以强制编译微信为例

强制编译所有软件包

cmd package compile -m speed -f -a

用没有 root 权限的工作机 Reno 进行编译

清除配置文件数据并移除编译的代码则需要 root 权限:

su #获取 root 权限

cmd package compile --reset com.tencent.mm #清除微信的被编译代码

cmd package compile --reset -a #清除所有被编译的代码

无论是编译还是清除代码,都会耗费大量手机性能,且耗时较长。建议选取个别高频第三方应用进行编译。

小结

无论是我们之前深度 介绍 过的 Project Mainline,还是本文介绍的云端下发应用的编译优化配置文件,或是将应用拆分分发的 App Bundle 特性,Google 把越来越多的优化工作放在了云端,而这一切是身在国内的我们无法享受到的。国内厂商该如何弥补这一块缺失?是不惜碎片化自己推出解决方案,还是联合广大国内开发者一起寻找解决方案?

参考资料:

题图来自 Firebase Blog

> 下载少数派 客户端、关注 少数派公众号 ,了解更多玩机技巧 🚀

> 特惠、好用的硬件产品,尽在 少数派sspai官方店铺 🛒