dex2oat 与编译产物:dex、oat、vdex 与 profile
2026/8/9大约 3 分钟运行时Android 14dex2oatoat编译
dex2oat 与编译产物:dex、oat、vdex 与 profile
上一章建立了全景。这一章回答:dex2oat 做什么,oat、vdex、profile 各是什么, 安装期与后台编译如何配合?
dex、vdex 与 oat 承担不同角色
| 常见误解 | 正确理解 |
|---|---|
| oat 是“新的 APK” | oat 是 dex 的编译产物,与 APK 共存 |
| 编译一次全量 AOT | 默认按 profile 编译热点,后台再补全 |
| 验证可有可无 | 验证是安全与正确性前提,失败会阻止加载 |
核心结论
- dex2oat 把 dex 编译为 oat,并生成 vdex。
- 编译策略:verify(只验证)、speed-profile(按 profile)、speed(全量)。
- 安装期编译 + 后台编译(bg-dexopt)分时完成。
- profile 记录热点方法,指导 JIT/AOT 编译。
- 编译越充分启动越快,但安装与存储成本越高。
编译主链
逐步解释:
- 触发:安装或更新时启动编译。
- 验证:检查 dex 正确性,生成 vdex。
- 编译:按策略生成 oat。
- 落盘:产物进入包目录。
- 后台补齐:空闲时按 profile 补编译。
编译策略速查
| 策略 | 行为 | 场景 |
|---|---|---|
| verify | 只验证 | 快速安装 |
| speed-profile | 按 profile 编译热点 | 默认平衡 |
| speed | 全量编译 | 性能优先 |
cmd package compile 可以手动切换策略,用于验证编译对启动的影响。
源码证据
阅读目标:确认 dex2oat 入口。
正文指针:art/dex2oat/dex2oat.cc 的主流程;art/runtime/ 的编译产物加载。
// art/dex2oat/dex2oat.cc(伪代码,行号以 r75 为准)
int main(int argc, char** argv) {
// 解析编译策略,生成 oat/vdex
}这段代码证明: dex2oat 是独立编译程序;产物由 ART 在运行时加载,编译策略 直接影响启动路径。
验证与排障
环境:开发设备或模拟器;以下命令不需要 root。
adb shell cmd package compile -m speed <包名>
adb shell dumpsys package <包名> | grep -E "codePath|primaryCpuAbi"
adb shell ls -l /data/app/<包名>-*/oat/
adb logcat -v threadtime | grep -E "dex2oat|BgDexopt"cmd package compile 切换策略;包目录 oat 子目录看产物。启动慢先确认编译状态, 再看是否缺 profile 或后台编译未完成。
常见误区
- “oat 是新的安装包”:是编译产物。
- “默认全量 AOT”:默认 speed-profile。
- “验证可有可无”:验证失败会阻止加载。
- “编译一次永久有效”:更新与清理会重建。
延伸问题
- baseline profile 如何加速冷启动?
- 后台编译(bg-dexopt)的调度条件是什么?
- 编译产物占用多少存储,如何平衡?
- 不同 ABI 的 oat 如何管理?
源码入口
| 文件 | 关键位置 | 作用 |
|---|---|---|
art/dex2oat/dex2oat.cc | 主流程 | 编译 |
art/runtime/ | 产物加载 | 执行 |
cmd package compile | 命令行 | 策略切换 |
oat/ 目录 | 产物 | 编译结果 |
公共路径:art/。行号以 r75 检索为准。
这些产物如何参与实际运行,见 ART 执行模式。