上一篇聊了无障碍开发,这篇回到性能方向。启动优化做过的人都知道,冷启动从点击图标到首帧渲染的每一毫秒都是抠出来的。AOT 编译、异步初始化、延迟加载这些手段用完后,Baseline Profiles 是下一层的优化。
先理解 ART 的编译模式
Android Runtime(ART)有三种编译模式:
解释执行(Interpreter):逐行解释字节码,最慢。
JIT(Just-In-Time):运行时动态编译热点代码为机器码,下次执行更快。
AOT(Ahead-Of-Time):安装时或空闲时预编译为机器码,最快但占存储。
Android 7+ 默认用 JIT + AOT 混合模式。App 首次启动时走解释 + JIT,系统在后台收集"热点方法"信息,空闲时用 dex2oat 做 AOT 编译。
问题在于:AOT 编译哪些代码由系统决定,而系统收集的热点信息可能不准确,尤其冷启动路径的代码可能还没被识别为"热点"。
Baseline Profile 是什么
Baseline Profile 是开发者主动提供给系统的 AOT 编译列表。你告诉 ART:"这些代码路径在启动时一定会走,请提前编译好。"
效果立竿见影:Jenkins 上的 Benchmark 数据显示,使用 Baseline Profile 后冷启动速度平均提升 20-30%,部分场景能到 40%。
生成 Baseline Profile
Google 提供了 Macrobenchmark 库来自动化生成 Profile:
1. 添加依赖
// build.gradle (app module)
android {
benchmark {
baselineProfile {
// 匹配需要生成 profile 的 variant
matchingVariants += "release"
}
}
}
2. 创建 Benchmark 测试
@ExperimentalBaselineProfilesApi
class BaselineProfileGenerator {
@Test
fun generate() = baselineProfile(rule = activityRule) {
collect("com.example.app") {
// 模拟启动路径
pressHome()
startActivityAndWait()
// 模拟用户操作,覆盖更多代码路径
device.findObject(By.text("首页")).click()
device.findObject(By.text("我的")).click()
}
}
}
3. 运行生成
在 Android Studio 中运行这个测试,生成 baseline-prof.txt 文件。这个文件包含了需要 AOT 编译的类和方法签名。
4. 集成到 App
// build.gradle
android {
sourceSets {
getByName("release") {
assets.srcDirs("src/release/baseline-profile")
}
}
}
将生成的 baseline-prof.txt 放到 src/release/assets/ 下,打包时会被嵌入 APK。安装时 ART 会读取这个文件并提前编译相关代码。
Macrobenchmark 性能测试
Baseline Profile 的生成依赖 Macrobenchmark,但 Macrobenchmark 本身也是强大的性能测试工具:
@ExperimentalBaselineProfilesApi
class StartupBenchmark {
@get:Rule
val benchmarkRule = MacrobenchmarkRule()
@Test
fun startupCompilationNone() = benchmarkRule.measureRepeated(
packageName = "com.example.app",
metrics = listOf(StartupTimingMetric()),
iterations = 5,
startupMode = StartupMode.COLD
) {
pressHome()
startActivityAndWait()
}
}
StartupTimingMetric 会报告:
timeToInitialDisplay:从启动到首帧渲染timeToFullDisplay:从启动到内容完全展示
你可以用这个框架测试不同优化手段的效果,比如对比加不加 Baseline Profile 的差异。
Cloud Profile
Android 12 引入了 Cloud Profile 机制。Google Play 云端收集用户运行时的热点方法,在后续版本中自动给新用户做 AOT 编译。
但 Cloud Profile 有延迟——新版本发布后需要几天的数据积累才能生效。Baseline Profile 可以让新版本发布当天就享受 AOT 加速,不需要等 Cloud Profile 数据。
两者是互补关系:Baseline Profile 覆盖已知关键路径,Cloud Profile 覆盖用户实际使用的长尾路径。
实际效果和注意事项
我们在一个日活百万的电商 App 上实测:
冷启动 timeToInitialDisplay 从 850ms 降到 620ms(-27%)
首页 RecyclerView 滑动流畅度提升 15%(首帧更快渲染,后续 JIT 也预热了)
注意事项:
Profile 要定期更新。版本迭代后代码路径会变化,旧 Profile 可能不准确。建议在 CI 流程中定期跑 Benchmark 重新生成。
Profile 不能包含太多方法。ART 有编译时间限制,太多方法会拉长安装时间。控制在几百个方法以内。
Profile 对 debug 模式无效。因为 debug 包是 JIT 模式,不做 AOT。
不要只靠 Profile。启动优化的根本还是减少启动路径上的工作量——延迟初始化、异步加载、按需创建。
其他启动优化手段回顾
在 Baseline Profile 之外,也别忘了基础工作:
Jetpack App Startup:统一初始化入口,支持自动按依赖顺序初始化
启动框架设计:有向无环图(DAG)管理初始化任务,区分同步/异步/延迟
黑屏问题:配置
windowBackground为带 Logo 的 drawable,避免白屏Splash Screen API(Android 12):系统提供的启动动画方案,体验更统一
小结
Baseline Profile 是当前最有效的启动优化手段之一,投入产出比高。配合 Macrobenchmark 做量化测量,形成"测量-优化-验证"的闭环。但别忘了优化的根本是减少启动路径的工作量,Profile 只是让已有代码跑得更快。
下一篇聊聊 Android CI/CD 的实践。