Google I/O : 使用 Baseline Profiles 优化启动性能
前言
应用的启动优化是Android
性能优化中的一个常见问题,除了常规的一些优化手段,在本次Google/IO
大会还介绍了通过Baseline Profiles
来优化启动速度。
本文主要包括以下内容:
Baseline Profiles
是什么?如何使用 Baseline Profiles
?使用 Baseline Profiles
的效果怎么样?
Baseline Profiles
是什么?
Android 9
在 Play Cloud
中引入了 ART
优化Profiles
文件,以缩短应用启动时间。平均而言,我们发现,当云Profiles
文件可用时,应用程序的冷启动速度至少快 15%。
Profiles
文件如何工作?
当应用程序在安装或更新后首次启动时,其代码在解释模式下运行(也就是JIT
)。在 APK
中,Java
和 Kotlin
代码被编译为 dex
字节码,但由于存储和加载完全编译的App
的成本,并未完全编译为机器码。 应用程序中经常使用的类和方法,以及用于应用程序启动的类和方法,都记录在Profiles
中。一旦设备进入空闲模式,ART
就会根据这些Profiles
编译应用程序。这加快了后续应用程序的启动。
从 Android 9
开始,Google Play
还提供 Cloud Profiles
。当应用在设备上运行时,由 ART
生成的配置文件由 Play
商店应用上传并在云端聚合。一旦为应用程序上传了足够的配置文件,Play
应用程序就会使用汇总的配置文件进行后续安装。
存在的问题
虽然Cloud Profiles
在可用时很棒,但在安装应用程序时并不总是可以使用。收集和汇总配置文件通常需要几天时间,如果你的App
是每周更新时,就可能在Cloud Profile
可用之前就发生更新了。因此,Google Android
团队开始寻找其他方法来改善Profiles
的延迟。
解决方案
Baseline Profiles
是一种新的机制,可提供可在 Android 7
及更高版本上使用的配置文件。Baseline Profiles
是由 Android Gradle
插件使用生成的 ART
配置文件,示例如下所示:
HSPLandroidx/compose/runtime/ComposerImpl;->updateValue(Ljava/lang/Object;)V
HSPLandroidx/compose/runtime/ComposerImpl;->updatedNodeCount(I)I
HLandroidx/compose/runtime/ComposerImpl;->validateNodeExpected()V
PLandroidx/compose/runtime/CompositionImpl;->applyChanges()V
HLandroidx/compose/runtime/ComposerKt;->findLocation(Ljava/util/List;I)I
Baseline Profiles
是在构建期间创建的,作为 APK
的一部分提供给 Play Store
,然后在下载应用程序时从 Play Store
发送给用户。当云配置文件尚不可用时,它们填补了 ART
云配置文件管道中的空白,并在它们可用时自动与云配置文件合并。
Baseline Profiles
的最大好处之一是它们可以在本地开发和测试,因此开发人员可以看到用户的实际体验。同时从Android 7
就已经支持了,而Cloud Profiles
只支持Android 9
以后的版本
如何使用Baseline Profiles
?
所有应用程序和库开发人员都可以从Baseline Profiles
中受益。理想情况下,开发人员为其最关键的用户路径创建配置文件,以确保这些关键路径具有始终如一的快速性能,无论云配置文件是否可用。
关于如何创建Baseline Profiles
的详细步骤,可查看:创建基准配置文件
在通过以上方式生成了配置文件之后,将生成的文件重命名为baseline-prof.txt
,并将其复制到应用模块的 src/main
目录,就可以生效了
如果您现在还没有准备好为您的应用程序生成Baseline Profiles
,您也可以通过更新依赖项来从中受益。如果您使用AGP 7.1.0-alpha05
或更高版本进行构建,您将获得包含在您的 APK
中的Baseline Profiles
,这些配置文件已经由库(例如 Jetpack
)默认提供。Google Play
在安装时使用这些配置文件编译您的应用程序。
使用Baseline Profiles
的效果怎么样?
第三方库的代码在默认情况下是没有完全编译的,如果它在启动的关键路径上做了大量工作,可能会带来一些性能问题。
比如Jetpack Compose
是一个 UI
库,它不是 Android
系统的一部分,因此在安装时并未完全编译,这与许多 Android View
工具包代码不同。这也是Compose
在可能刚启动时比较慢的原因.
为了解决这个问题,Compose
默认提供了Baseline Profiles
,可减少 Compose
应用程序的启动时间和卡顿。
Gogle
在Google Map
与Google Play
中都使用了Baseline Profiles
,根据Google I/O
上给出的数据,可以达到30%左右的启动性能提升
测量性能提升
由于Jetpack
包和Compose
都提供了默认的Baseline Profiles
配置,因此你自定义的Baseline Profiles
不一定会达到最佳效果,在自定义时必须也要编写相关性能测试用例
abstract class AbstractStartupBenchmark(private val startupMode: StartupMode) {
@Test
fun startupNoCompilation() = startup(CompilationMode.None())
@Test
fun startupBaselineProfileDisabled() = startup(
CompilationMode.Partial(baselineProfileMode = Disable, warmupIterations = 1)
)
@Test
fun startupBaselineProfile() = startup(CompilationMode.Partial(baselineProfileMode = Require))
@Test
fun startupFullCompilation() = startup(CompilationMode.Full())
}
如上所示,分别测试CompilationMode.None
,CompilationMode.Full
,CompilationMode.Partial
等情况下的启动性能,根据结果分析是否需要自定义Baseline Profiles
总结
通过Baseline Profiles
,将应用启动时的关键路径相关代码提前进行编译,可以加快启动速度与首次加载速度。您可以更新到AGP 7.1.0-alpha05
或更高,来享受到Jetpack
库提供的默认配置,也可以自定义Baseline Profiles
,但是在自定义后需要通过Macrobenchmark
库测量性能,以衡量自定义配置是否有效
参考资料
Google I/0 应用性能的新动态
Improving App Performance with Baseline Profiles