在 Android 虚拟机(ART)中,ArtMethod
、OatFile::OatMethod
和 ClassLinker
是三个核心组件,它们在方法管理、代码执行和类加载过程中扮演着重要角色。本文将深入探讨它们的工作原理及其在 ART 中的作用。
1. ArtMethod:Java 方法的内部表示
ArtMethod
是 ART 虚拟机中表示 Java 方法的内部结构。它包含了方法的元数据和执行信息,例如:
- 方法名和签名:标识方法的名称和参数。
-
访问标志:如
public
、private
等。 - 字节码或本地代码指针:指向方法的可执行代码。
- 所属类:方法所属的类。
ArtMethod
在方法调用时用于查找和执行代码。它的一个重要字段是 Entry Point(入口点),指向方法的可执行代码入口。根据方法的编译状态,入口点可能是:
- 解释执行:指向解释器的代码。
- AOT 编译:指向 AOT 编译生成的本地机器码。
- JIT 编译:指向 JIT 编译生成的本地机器码。
2. OatFile::OatMethod:AOT 编译方法的存储格式
OatFile::OatMethod
是 ART 中存储已编译方法的格式。它包含以下信息:
- 编译后的本地代码:AOT 编译生成的机器码。
- 元数据:如调试信息和内联缓存。
OatFile
是存储 AOT 编译结果的容器,而 OatMethod
则是其中表示单个方法的结构。在 AOT 编译模式下,ArtMethod
的 Entry Point
会指向 OatFile::OatMethod
中存储的本地代码。
3. ClassLinker:类的加载、链接和初始化
ClassLinker
负责类的加载、链接和初始化。它的主要功能包括:
- 类加载:从 DEX 文件加载类定义。
- 类链接:解析类依赖,准备方法表和静态字段。
- 类初始化:执行类的静态初始化块。
在类加载时,ClassLinker
会从 DEX 文件加载类和方法。如果存在 AOT 编译文件(OAT 文件),ClassLinker
会从 OatFile
中加载 OatMethod
,并将其入口点信息设置到 ArtMethod
的 Entry Point
字段。
4. LinkCode 函数:设置 ArtMethod 的 Entry Point
LinkCode
函数是设置 ArtMethod
的 Entry Point
的关键逻辑之一。以下是它的主要工作流程:
- 检查方法是否可链接:如果方法不可调用(如抽象方法),则设置一个抛出异常的入口点。
-
从 OatFile::OatMethod 获取代码:如果存在
oat_class
,则从OatFile::OatMethod
中获取 AOT 编译的本地代码(quick_code
)。 -
设置方法的 Entry Point:调用
InitializeMethodsCode
将quick_code
设置为ArtMethod
的EntryPointFromQuickCompiledCode
。 -
处理 Native 方法:对于 Native 方法,设置 JNI 调用的入口点(
EntryPointFromJni
)。
5. Android 虚拟机的三种执行方式
Android 虚拟机支持三种主要的程序执行方式:解释执行(Interpretation)、即时编译(JIT,Just-In-Time) 和 预先编译(AOT,Ahead-Of-Time)。以下是它们的详细说明和比较:
5.1 解释执行(Interpretation)
- 工作原理:解释器逐条读取字节码,并动态转换为机器码执行。
- 优点:启动速度快,内存占用低。
- 缺点:执行效率低。
- 使用场景:主要用于 Android 5.0 之前的 Dalvik 虚拟机。
5.2 即时编译(JIT,Just-In-Time)
- 工作原理:在程序运行时动态将热点代码编译为本地机器码。
- 优点:动态优化,节省存储空间。
- 缺点:运行时开销大。
- 使用场景:适用于长时间运行的应用。
5.3 预先编译(AOT,Ahead-Of-Time)
- 工作原理:在应用安装时,将字节码预先编译为本地机器码。
- 优点:执行效率高,减少运行时开销。
- 缺点:安装时间较长,存储占用高。
- 使用场景:适用于对性能要求高的场景。
5.4 三种方式的比较
特性 | 解释执行(Interpretation) | 即时编译(JIT) | 预先编译(AOT) |
---|---|---|---|
编译时机 | 运行时逐条解释 | 运行时动态编译热点代码 | 安装时预先编译 |
执行效率 | 低 | 较高 | 高 |
启动速度 | 快 | 较快 | 较慢(安装时编译) |
存储占用 | 低 | 中等 | 高 |
运行时开销 | 无编译开销,但解释开销高 | 有编译开销 | 无编译开销 |
适用场景 | 低资源设备、初始阶段 | 长时间运行的应用 | 高性能要求的应用 |
6. 解释执行与 JavaScript 执行的比较
解释执行和早期的 JavaScript 执行非常相似,都是逐条解释代码并动态执行。然而,现代 JavaScript 引擎已经引入了 JIT 编译和优化技术,执行效率大幅提升。以下是它们的相似之处和不同点:
6.1 相似之处
- 逐条解释执行:两者都是逐条读取代码并动态执行。
- 无需预先编译:代码无需预先编译为机器码。
- 启动速度快:适合快速加载和执行。
- 动态特性支持:支持动态加载和执行代码。
6.2 不同点
- 执行效率:现代 JavaScript 引擎通过 JIT 编译大幅提升了执行效率。
- 优化能力:现代 JavaScript 引擎具有复杂的优化能力。
- 应用场景:解释执行主要用于 Android 虚拟机,而 JavaScript 执行主要用于浏览器环境。
7. 总结
ArtMethod
、OatFile::OatMethod
和 ClassLinker
是 ART 虚拟机中的核心组件,它们在方法管理、代码执行和类加载过程中发挥着重要作用。通过理解它们的工作原理,我们可以更好地掌握 Android 虚拟机的运行机制。此外,Android 虚拟机的三种执行方式(解释执行、JIT 和 AOT)各有优缺点,适用于不同的场景。随着技术的发展,现代 JavaScript 引擎已经超越了传统的解释执行模式,通过 JIT 编译和优化技术大幅提升了执行效率。