性能
启动缺页多,就做二进制重排
启动链路的函数如果散在很多内存页上,每次缺页都要读盘和解密。把它们排到连续页上,能少做这些事。
pre-main 里除了动态库和 +load,还有一块容易被忽略的时间:Page In。进程按页访问内存。启动时用到的两个函数如果落在不同页,系统就要做两次缺页,把页读进来并做解密校验。函数散得越开,这种中断越多。
重排在做什么
把启动链路上真正会走到的符号排到连续的页里,让一次读入覆盖更多马上要用的代码。链接器认的是 order file。Xcode 的 Order File 会在链接时按这个文件里的符号顺序生成 Mach-O。
- 先收集启动路径上的符号,再生成 order file。没有收集,重排没有依据。
- 只 Hook objc_msgSend,能拿到 Objective-C 和标了 @objc dynamic 的 Swift,C、C++、普通 Swift 和 Block 会漏。
- 要覆盖这些,用 Clang 插桩去记真正执行过的函数。
收益和机型、系统、启动路径有关。先在同一台真机、同一种冷启动上比重排前后的 pre-main,不要拿一次 Debug 启动当结果。业务天天加启动代码时,order file 会过期,要放进构建,而不是手工维护一次就忘。
和别的启动优化怎么排
动态库太多、+load 里做重活,通常比缺页更先看见。重排是这些做完之后,还想再抠 pre-main 时用的。它不代替“把初始化挪出启动”。