启动优化-Rebase与Bind
Rebase和Bind是Pre-main阶段的重要步骤,用于修正程序中的指针地址。ObjC类、方法、协议等元数据越多,需要修复的指针越多,启动时间越长。 基本概念 由于ASLR(Address Space Layout Randomization)技术,App每次启动时加载到内存的地址都是随机的,因此需要进行地址修正。关于Rebase和Bind的底层原理,可以参考Mach-O的链接、装载与库。 Rebase(重定位) 修正指向Mach-O内部的指针,将编译时的地址加上ASLR偏移量。 Bind(绑定) 修正指向Mach-O外部的指针,查找符号表,绑定到正确的外部符号地址。 flowchart LR subgraph compile["编译时 (Mach-O文件)"] A1["内部指针: 0x1000(指向内部数据)"] A2["外部符号: _objc_msgSend(待绑定)"] end subgraph runtime["运行时 (内存中)"] B1["内部指针: 0x1000 + slide(Rebase修正)"] B2["外部符号: 实际地址(Bind绑定)"] end A1 -->|"Rebase"| B1 A2 -->|"Bind"| B2 问题分析 以下因素会增加Rebase/Bind的工作量: 因素 影响 ObjC类数量 每个类都有元数据需要修正 Swift类数量 Swift类在Apple平台也会生成ObjC兼容的元数据,同样需要修正 ObjC方法数量 方法列表中的指针需要修正 Category数量 Category的方法列表需要绑定 C++虚函数 虚函数表中的指针需要绑定 全局变量 指向其他符号的全局变量需要绑定 关于缓存机制: 系统动态库:Rebase/Bind 操作已在 dyld shared cache 中预先完成,不会在 App 启动时执行 App 动态库:dyld 3 的 Launch Closure 会缓存 Rebase/Bind 的元数据信息(哪些指针需要修正、修正方式等),但 Rebase/Bind 操作本身仍需每次启动时执行,因为 ASLR slide 每次启动都不同 因此,减少 ObjC 类、Category、C++ 虚函数等仍然是有效的优化手段。 ...