启动优化
问题
iOS App 冷启动的完整过程?如何做启动优化?
答案
冷启动两阶段
pre-main 优化
| 优化项 | 方法 |
|---|---|
| 减少动态库 | 合并动态库(Apple 建议 < 6 个自定义动态库) |
| 减少 ObjC 类 | 删除无用类,合并小类 |
| 避免 +load | 改用 +initialize 或延迟初始化 |
| 二进制重排 | 减少 Page Fault(Clang 插桩获取启动调用顺序) |
main 之后优化
// ❌ didFinishLaunching 中初始化所有 SDK
func application(_ application: UIApplication,
didFinishLaunchingWithOptions launchOptions: ...) -> Bool {
initCrashSDK() // 必须立即
initNetworking() // 必须立即
initAnalytics() // 可延迟
initPushSDK() // 可延迟
initAdSDK() // 可延迟
return true
}
// ✅ 分级初始化
func application(...) -> Bool {
// 第一优先级:崩溃收集、网络
initCrashSDK()
initNetworking()
// 延迟到首屏渲染后
DispatchQueue.main.async {
self.initAnalytics()
self.initPushSDK()
}
// 延迟到用户空闲时
DispatchQueue.main.asyncAfter(deadline: .now() + 3) {
self.initAdSDK()
}
return true
}
度量
// Xcode: Edit Scheme → Run → Arguments → Environment Variables
// 添加 DYLD_PRINT_STATISTICS = 1
// 控制台输出 pre-main 耗时
// 代码测量 main 后耗时
let start = CFAbsoluteTimeGetCurrent()
// ... 首屏加载后
let elapsed = CFAbsoluteTimeGetCurrent() - start
常见面试问题
Q1: 二进制重排是什么原理?
答案:App 启动时会访问大量函数,如果这些函数分散在不同内存页,会产生多次 Page Fault(缺页中断,每次约 0.1-1ms)。二进制重排把启动时调用的函数排列到连续内存页中,减少 Page Fault 次数。通过 Clang 插桩(__sanitizer_cov_trace_pc_guard)记录启动函数调用顺序,生成 order 文件给链接器。