Runtime是一个软件层,负责管理移动应用代码的执行:分配内存、处理异常、启动垃圾回收并调度方法调用。没有运行时,任何应用都无法运行——它是编译代码与操作系统之间的中间层。根据Android Developer Documentation, 2025,运行时环境是平台的关键元素,决定了性能和兼容性。
要点
Runtime(运行时环境)是在程序启动后确保其执行的基础设施。在移动开发语境中,运行时包括类加载器、内存分配器、垃圾回收器、方法分发器和异常处理器。没有这个中间层,操作系统无法执行Dalvik字节码或Objective-C消息。
移动平台使用不同的运行时实现。Android使用ART(Android Runtime),采用混合AOT/JIT编译。iOS使用Objective-C Runtime——一种基于消息传递和SEL标识符的动态系统。两种方法解决同一个问题:在特定设备上以最大性能执行开发者的代码。
根据Google I/O 2024,Android Runtime在全球设备上每天处理超过100亿个方法。运行时的性能直接影响应用启动速度、动画流畅度和电池消耗。每次方法调用、每次内存分配和每个垃圾回收周期都经过运行时层。
运行时系统包括五个关键组件:类加载器、内存管理器、解释器或编译器、方法分发器和安全系统。每个组件在代码执行过程中都履行严格定义的功能。
当用户启动应用时,ClassLoader将DEX文件(Android)或Mach-O二进制文件(iOS)加载到内存中。在Android中,这一阶段包括字节码验证:运行时检查代码不包含不安全的指令、不越出数组边界并遵守类型。验证是防止恶意代码执行的关键安全步骤。
Memory Manager为对象分配和释放内存。在Android中,ART使用带分代收集的并发垃圾回收器:年轻对象检查更频繁,年老对象更少。Objective-C Runtime采用自动引用计数(ARC),编译器自动插入retain/release调用。
Method dispatcher决定调用哪个方法实现。在静态语言(Kotlin、Swift)中,分发通过vtable——虚方法表完成。在动态语言(Objective-C)中,消息经过objc_msgSend,它会在类及其超类中查找实现。结果缓存到method cache中以加速重复调用。
Android Runtime(ART)是执行Android应用DEX字节码的虚拟机。ART在Android 5.0 Lollipop中取代了Dalvik,提供AOT编译:应用在安装期间一次性编译为机器码。这消除了每次启动时JIT编译的开销。
从Android 7.0 Nougat开始,ART采用混合方法。安装时仅对常用方法(hot methods)执行JIT编译,其余代码被解释。后台进程(profile-guided optimization)分析哪些方法被调用最频繁,并在设备空闲时将其AOT编译。这缩短了安装时间,同时保证了高性能。
ART还包括AOT compiler(dex2oat),将DEX文件转换为带ARM64机器码的ELF二进制文件。编译分三个优化级别:quicken(快速)、optimize(中等)和everything(完整)。默认情况下Android应用optimize,在编译速度和代码性能之间取得平衡。
class RuntimeExample {
fun measureExecutionTime() {
val start = System.nanoTime()
// 调用由ART编译的方法
processData()
val end = System.nanoTime()
println("执行时间:${end - start} ns")
}
}在上面的示例中,System.nanoTime()是一个原生方法,其调用通过ART运行时调度到Linux内核。ART将Kotlin字节码转换为设备处理器执行的ARM64指令。这个过程对开发者不可见,但优化它是Android Platform团队的关键任务。
基于配置文件的优化是ART收集方法使用配置文件的机制。文件profiles/
开发者可以在其Gradle项目中启用baseline profiles。这些是手写注解,指示ART在安装后立即AOT编译哪些方法。Baseline profiles无需等待后台配置即可将首次启动缩短40%。
Objective-C Runtime是确保Objective-C代码在iOS和macOS上执行的动态库。其核心是objc_msgSend函数,它实现消息传递:对象不是直接调用方法,而是发送带选择器的消息,运行时确定应执行哪个实现。
每个Objective-C对象都包含指向类的isa指针,类则维护dispatch table(分发表),将选择器(SEL)映射到实现(IMP)。当调用方法时,objc_msgSend沿链移动:类→超类→NSObject,直到找到IMP。如果找不到实现,运行时调用转发机制,它可以拦截消息或生成异常。
Objective-C Runtime还支持method swizzling——在运行期间替换现有选择器的IMP。这是AOP库和监控工具中使用的强大机制,但由于影响整个应用而需要谨慎。
@interface RuntimeDemo : NSObject
- (void)printClassInfo;
@end
@implementation RuntimeDemo
- (void)printClassInfo {
// objc_getClass — runtime函数
Class cls = objc_getClass("RuntimeDemo");
unsigned int count;
Method *methods = class_copyMethodList(cls, &count);
NSLog("方法数量:%d", count);
}
@end代码演示了对Objective-C Runtime API的直接访问:objc_getClass按名称获取类对象,class_copyMethodList提取所有方法的列表。这是运行中的反射——在运行期间访问类的元数据。这种方法在XCTest中用于动态注册测试。
isa pointer是指向对象类的指针,存储在每个对象的前8个字节中。从iOS 12开始,Apple引入了isa-swizzling以优化:isa的低位对对象状态的附加信息进行编码。Tagged pointers是另一种优化,其中最多60位的值(NSNumber、NSDate)直接存储在指针中,而无需在堆中分配对象。这将内存管理器的负载降低30%。
JIT(Just-In-Time)和AOT(Ahead-Of-Time)是将字节码编译为机器码的两种方法。JIT在应用运行期间编译代码,分析热点并即时优化。AOT预先编译所有代码——在应用安装时或由开发者完成。
| 特征 | JIT | AOT |
|---|---|---|
| 编译时间 | 运行期间 | 安装/构建时 |
| APK/IPA大小 | 更小(仅字节码) | 更大(机器码) |
| 启动速度 | 更低(需要编译) | 更高(代码可立即执行) |
| 针对设备的优化 | 是(自适应) | 有限(通用) |
| RAM消耗 | 更高(内存中的编译器) | 更低 |
ART的混合方法(Android 7+)被认为是最优的:应用对很少调用的方法使用解释器,对hot方法使用JIT,对来自基于配置文件优化的方法使用AOT。相反,iOS通过LLVM使用严格的AOT:Swift和Objective-C在Xcode的构建阶段编译为机器码。
根据Apple Developer Documentation, 2024,Swift运行时为应用大小增加约15 MB。Flutter使用自己的Dart VM,其中JIT编译在debug模式下用于热重载,AOT在release模式下用于最大性能。React Native使用Hermes——带AOT编译的JavaScript引擎,将启动时间缩短50%。
ARM64 Runtime是机器码与设备处理器交互的层面。大多数现代移动设备运行在ARM64(aarch64)处理器上。运行时将字节码或原生调用转换为CPU执行的ARM64指令。
运行时使用的关键ARM64寄存器:x0–x7(函数参数)、x8(间接结果)、x30(返回地址)、sp(堆栈指针)、fp(帧指针)。ART生成的代码遵守ARM64 Procedure Call Standard:所有方法调用都经过处理器架构定义的协议。
理解ARM64 ABI对性能优化很重要:内联缓存、分支预测和内存中的代码对齐直接影响运行时的运行速度。分析工具(Android Studio Profiler、Instruments)显示代码的哪些部分在运行时中花费最多时间——正是优化这些部分能带来最大提升。
// ART生成的ARM64汇编示例
// 带两个参数的方法调用
mov x0, x23 // self (this)
mov x1, x24 // param1
mov x2, x25 // param2
bl methodEntryPoint // 通过runtime调用
str x0, [sp, #8] // 保存结果在此示例中,ARM64指令mov将参数传输到x0–x2寄存器,bl调用方法的入口点,str保存返回值。运行时为每次方法调用生成此类指令,通过devirtualization和inlining优化序列。
Runtime overhead是动态分发的不可避免代价。每次通过运行时的方法调用都需要:在dispatch table中查找实现、检查类型、调用IMP并返回结果。测量表明,运行时在Objective-C中每次调用增加10–50 ns,在ART中增加5–20 ns。
为减少开销,开发者使用monomorphic inlining(ART)和method caching(Objective-C)。Kotlin/Native和Swift直接编译为ARM64,完全消除运行时层,但失去动态能力——反射、swizzling、类动态加载。
常见问题
SDK(软件开发工具包)是开发应用的成套工具(编译器、库、实用程序)。Runtime是已经开发好的应用在设备上执行的环境。开发者需要SDK,用户需要runtime。
不能——runtime是操作系统的一部分,用户无法替换。ART内置于Android Framework,Objective-C Runtime内置于iOS。开发者可以选择语言(无runtime的Kotlin/Native)或使用Flutter中的Dart VM等虚拟机。
是的,runtime影响能量消耗。ART中的垃圾回收和Swift运行时使用CPU,增加电量消耗。并发GC和iOS中的tagged pointers等优化将runtime对电池的影响降低20–30%。
Runtime error是运行期间发生的错误:空指针异常、索引越界、除零。与编译时错误不同,这些错误在构建时无法发现。通过try-catch块或崩溃报告(Firebase Crashlytics、Sentry)捕获。
Swift runtime比Objective-C更轻量:默认不支持动态分发,使用无堆分配的值类型(struct),且没有消息转发。Swift方法如果没有用@objc dynamic标记,则直接通过vtable调用。这在基准测试中提供高达5倍的加速。
总结
我们将开发一款交钥匙移动应用程序
IT Sectr自2017年以来为初创企业和企业打造iOS和Android应用程序。我们将为您提供咨询并提出最佳解决方案。