🚀 ART 启动镜像双文件架构详细图解

Boot.art & Boot.oat 完整技术剖析

📦 boot.art
堆快照文件 (Heap Snapshot)
1
Image Header (镜像头)
  • Magic Number: "art\n" (0x0A747261)
  • Version: 当前版本号 (如 101)
  • OAT Checksum: boot.oat 的 SHA-1 校验和
  • Image Begin: 镜像加载基地址
  • Image Size: 总大小 (~40-80MB)
  • OAT File Begin: 对应 OAT 文件地址
  • Patch Delta: 地址重定位增量
2
Image Roots (根对象区)
  • DexCaches[]: DEX 文件缓存数组
  • ClassRoots[]: 核心类对象根引用
  • ClassLoader: 启动类加载器
  • SpecialRoots: 特殊对象(如 OutOfMemoryError)
3
Class Objects (类对象区)
  • Class Metadata: 类的完整元数据
  • VTable: 虚方法表 (Virtual Method Table)
  • IFTable: 接口方法表
  • Fields Layout: 字段布局信息
  • Access Flags: 访问标志 (public/final/etc)
  • Super Class: 父类引用
  • Class Loader: 所属类加载器
4
String Pool (字符串常量池)
  • Interned Strings: 系统级驻留字符串
  • Hash Table: 快速查找哈希表
  • UTF-16 Data: 实际字符数据
  • String Count: ~50,000+ 字符串
5
Static Fields (静态字段区)
  • Primitive Values: 基本类型静态字段
  • Object References: 对象引用型静态字段
  • 已初始化状态: 所有 <clinit> 已执行
  • 示例: String.CASE_INSENSITIVE_ORDER
6
Object Graph (对象图谱)
  • Object Headers: GC 标记位、类型指针
  • Reference Chains: 对象间引用链
  • Array Objects: 预分配数组对象
  • 总对象数: ~100,000+ 对象
⚙️ boot.oat
ELF 可执行文件 (Native Code)
1
ELF Header (ELF 文件头)
  • Magic: 0x7F 'E' 'L' 'F'
  • Class: ELFCLASS64 (64位)
  • Machine: EM_AARCH64 (ARM64)
  • Entry Point: 入口地址
  • Section Headers: 段表偏移
2
OAT Header (OAT 专有头)
  • Magic: "oat\n" (0x0A74616F)
  • Version: OAT 格式版本
  • Image Checksum: boot.art 校验和
  • DEX File Count: 包含的 DEX 数量
  • Instruction Set: ARM64/x86_64
  • Compiler Filter: speed/space/etc
3
.text 段 (代码段)
  • Machine Code: AOT 编译的 ARM64 指令
  • Method Code: 每个方法的本地代码
  • Trampoline: 跳转桩代码
  • Optimizations: 内联、循环优化
  • Size: ~30-50MB
  • Permissions: R-X (只读可执行)
4
.rodata 段 (只读数据)
  • String Literals: 代码中的字符串常量
  • Jump Tables: switch 语句跳转表
  • Exception Tables: 异常处理表
  • Debug Info: 调试信息(符号表)
5
.data.bimg.rel.ro (镜像引用表)
  • Class Pointers: 指向 boot.art 中类对象
  • String Pointers: 指向字符串池
  • Static Field Refs: 静态字段引用
  • 需要重定位: 加载时基地址修正
6
Symbol Table (符号表)
  • Method Symbols: 方法名 → 地址映射
  • Class Symbols: 类名 → 元数据映射
  • External Symbols: 外部库符号
  • Dynamic Linking: 动态链接信息
7
Inline Cache (内联缓存)
  • Type Profiles: 多态调用点类型信息
  • Receiver Types: 接收者类型集合
  • Devirtualization: 虚调用优化
↔️ 强关联绑定 (Checksum 验证)

📍 进程虚拟地址空间映射示意图

内核空间
0xFFFF...
栈区
(Stack)
mmap区
(动态库)
堆区
(App Heap)
boot.art
(mmap映射)
boot.oat
(代码段)
数据段
(Data/BSS)
代码段
(Text)

💡 boot.art 和 boot.oat 通过 mmap 直接映射到进程地址空间,实现零拷贝加载

🧠 内存布局详细结构

boot.art 内存分区

Image Header
偏移: 0x0000
大小: ~4KB
内容: 版本、校验和、大小信息
Image Roots Section
偏移: 0x1000
大小: ~16KB
内容: GC 根对象、DexCache、ClassLoader
Objects Section
偏移: 0x5000
大小: ~20-40MB
内容: 类对象、字符串对象、数组对象
对象数: ~100,000+ 个
Metadata Section
大小: ~10-20MB
内容: ArtMethod、ArtField 元数据
Bitmap Section
大小: ~2-4MB
内容: 对象引用位图、GC 标记位

boot.oat 段布局

ELF + OAT Header
偏移: 0x0000
大小: ~8KB
内容: ELF 魔数、段表、OAT 版本信息
.text (代码段)
偏移: 0x2000
大小: ~30-50MB
内容: ARM64 机器码指令
方法数: ~50,000+ 编译方法
权限: R-X (只读可执行)
.rodata (只读数据)
大小: ~5-10MB
内容: 字符串常量、跳转表、异常表
权限: R-- (只读)
.data.bimg.rel.ro
大小: ~2-5MB
内容: 指向 boot.art 的指针数组
重定位: 运行时需基地址修正
.symtab / .dynsym
大小: ~1-3MB
内容: 符号表、动态符号表
.bss (未初始化数据)
大小: ~1MB
内容: 运行时分配的全局变量区

⚡ 启动镜像加载工作流程

1
系统启动 - Init 进程启动 Zygote
Init 进程解析 init.rc,启动 Zygote 进程。Zygote 是所有应用进程的父进程。
2
Zygote 初始化 ART 虚拟机
加载 libart.so,创建 Runtime 实例,设置堆参数、GC 策略等。
// art/runtime/runtime.cc Runtime::Create("/system/framework/boot.art"); runtime_->Init();
3
映射 boot.art 到内存
使用 mmap() 系统调用,将 boot.art 以只读共享方式映射到虚拟地址空间。
// art/runtime/image.cc void* addr = mmap(nullptr, image_size, PROT_READ, MAP_SHARED, image_fd, 0); // 地址: 0x70000000 (示例)
4
加载 boot.oat 代码段
使用 dlopen() 加载 boot.oat,映射 .text 段到可执行内存区域。
// art/runtime/oat_file.cc OatFile::Open("/system/framework/boot.oat"); // .text 段权限: R-X // .rodata 段权限: R--
5
验证校验和 (Checksum)
对比 boot.art 中存储的 OAT checksum 与 boot.oat 文件的实际 checksum,确保版本匹配。
if (image_header->oat_checksum != oat_file->GetChecksum()) { LOG(FATAL) << "Boot image checksum mismatch!"; }
6
重定位指针引用
修正 boot.oat 中指向 boot.art 的所有指针,加上实际加载基地址偏移量。
for (auto ptr : relocation_table) { *ptr += image_base_address; } // 例: 0x1000 + 0x70000000 = 0x70001000
7
初始化 GC Roots
将 Image Roots 中的对象注册为 GC 根对象,确保垃圾回收时不会被误回收。
8
Zygote 进入就绪状态
启动镜像加载完成,Zygote 开始监听 Socket,等待 fork 子进程请求。所有后续应用进程通过 COW 继承这些只读共享内存。

📊 boot.art vs boot.oat 技术规格对比

对比维度 boot.art boot.oat
文件类型 自定义格式 (ART Image) 标准 ELF 格式
魔数标识 art\n (0x0A747261) oat\n (0x0A74616F)
典型大小 40-80 MB 30-60 MB
存储内容 Java 堆对象序列化数据 编译后的本地机器码
内存权限 R-- (只读,需 GC 扫描) .text: R-X, .rodata: R--
对象数量 ~100,000+ 对象 N/A (代码指令)
方法数量 N/A (仅类元数据) ~50,000+ 编译方法
加载方式 mmap(MAP_SHARED) dlopen()
共享特性 多进程物理内存共享 多进程共享代码段
校验机制 存储 boot.oat 的 checksum 存储 boot.art 的 checksum
更新触发 系统升级、ART 版本变更、dex2oat 参数改变

📦 boot.art 文件规格

文件扩展名 .art
页对齐 4KB (0x1000)
Header 版本 101-108 (Android 版本相关)
包含类数量 ~3,000-5,000 类
字符串池大小 ~5-10 MB
是否可修改 否 (只读共享)

⚙️ boot.oat 文件规格

文件扩展名 .oat
架构支持 ARM64, ARM, x86_64, x86
编译器 dex2oat (基于 LLVM)
编译模式 speed / speed-profile
指令集 AArch64 / x86-64
代码密度 ~0.6-1.2 KB/方法

🔗 关联与验证

校验算法 SHA-1 / Adler-32
版本绑定 严格绑定 (不可跨版本)
地址对齐 编译时预留重定位空间
失配后果 系统无法启动 (Bootloop)

⚡ 性能特性

加载耗时 ~50-100 ms
内存节省 300-800 MB (50 个进程)
代码执行速度 接近原生 C++ (95%+)
冷启动优化 减少 200-500 ms

📚 本图解基于 Android 14 (API 34) AOSP 源码分析绘制
💡 详细技术实现请参考: art/runtime/art/compiler/ 目录