写在前面: iOS底层原理探究是本人在平时的开发和学习中不断积累的一段进阶之
路的。 记录我的不断探索之旅,希望能有帮助到各位读者朋友。
目录如下:
- iOS 底层原理探索 之 alloc
- iOS 底层原理探索 之 结构体内存对齐
- iOS 底层原理探索 之 对象的本质 & isa的底层实现
- iOS 底层原理探索 之 isa - 类的底层原理结构(上)
- iOS 底层原理探索 之 isa - 类的底层原理结构(中)
- iOS 底层原理探索 之 isa - 类的底层原理结构(下)
- iOS 底层原理探索 之 Runtime运行时&方法的本质
- iOS 底层原理探索 之 objc_msgSend
- iOS 底层原理探索 之 Runtime运行时慢速查找流程
- iOS 底层原理探索 之 动态方法决议
- iOS 底层原理探索 之 消息转发流程
- iOS 底层原理探索 之 应用程序加载原理dyld (上)
- iOS 底层原理探索 之 应用程序加载原理dyld (下)
- iOS 底层原理探索 之 类的加载
- iOS 底层原理探索 之 分类的加载
- iOS 底层原理探索 之 关联对象
- iOS底层原理探索 之 魔法师KVC
- iOS底层原理探索 之 KVO原理|8月更文挑战
- iOS底层原理探索 之 重写KVO|8月更文挑战
- iOS底层原理探索 之 多线程原理|8月更文挑战
- iOS底层原理探索 之 GCD函数和队列
- iOS底层原理探索 之 GCD原理(上)
- iOS底层 - 关于死锁,你了解多少?
- iOS底层 - 单例 销毁 可否 ?
- iOS底层 - Dispatch Source
- iOS底层 - 一个栅栏函 拦住了 数
- iOS底层 - 不见不散 的 信号量
- iOS底层 GCD - 一进一出 便成 调度组
- iOS底层原理探索 - 锁的基本使用
- iOS底层 - @synchronized 流程分析
- iOS底层 - 锁的原理探索
- iOS底层 - 带你实现一个读写锁
- iOS底层 - 谈Objective-C block的实现(上)
- iOS底层 - 谈Objective-C block的实现(下)
- iOS底层 - Block, 全面解析!
- iOS底层 - 启动优化(上)
以上内容的总结专栏
细枝末节整理
前言
上一篇,我们从理论上分析了启动优化的知识点。总结了为什么二进制重排可以在启动时间进行优化(将启动时刻调用的函数放在一起,减少了缺页中断的次数);那么这里的难点是,我们如何知道启动时刻项目调用了哪些方法。好,整理下今天的思路,第一: 定位到,APP启动时刻调用的项目中的方法;第二:生成order文件;第三:配置二进制重排。
优化之前记录
整理
缺页中断是2578次 耗时 520.31ms;
一次缺页中断耗时 大概 0.2ms
冷启动时间 642.26ms
Clang插桩HOOK一切
这里是一份Clang13的文档 有一节 Tracing PCs (跟踪CPU执行到的代码)
通过Clang插桩我们可以跟踪到所有函数的执行,当然会包括APP启动时刻所调用的。
添加Clang插桩标记
实现如下函数:
start 和 stop 放的是符号的个数
前闭后开区间,所以stop-4
通过回调回来的数据信息,我们可以知道:
- 我们的项目中有 3 * 16+5+6 * 16 * 16+5 * 16 * 16 * 16 = 22069 个符号;
在 __sanitizer_cov_trace_pc_guard 回调中我们就可以拿到符号,我们就可以在这里将启动时刻调用的方法做保存,然后取出来,再生成 order 文件就可以了,下一步,我们开始收集启动时刻调用的方法
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
if (!*guard) return;
// 上一个函数的地址
void *PC = __builtin_return_address(0);
Dl_info info;
dladdr(PC, &info);
printf("%s\n", info.dli_sname);
// printf("fname-%s\nfbase-%p\nsname-%s\nsaddr%p\n\n\n\n",info.dli_fname, info.dli_fbase, info.dli_sname, info.dli_saddr);
}
收集调用方法
自定义存储结构体
定义符号结构体用来存储我们要收集的符号:
在 __sanitizer_cov_trace_pc_guard 回调中存储节点数据:
在 启动完成的地方 取出所有的节点数据并打印出来
注意这里存在以下问题,需要我们修复:
- 顺序是反向的
- 顺序有重复的
- 函数需要我们手动加下划线
生成order文件
处理完成上一步骤三个问题 , 就可以开始着手处理生成了我们需要的 order 文件了。
解决上一步骤存在的三个问题:
配置二进制重排
这里就可以去掉 Clang 插桩标记了
配置order文件
将我们生成的 order 文件 放到项目的根路径下,然后配置 Order file
配置好之后打开link map build 一下项目 验证:
完美,和我们的 order 文件顺序一致。
优化效果
File Backed Page In 从 2578次 减少到了 688次 145.08ms(减少了近74% 的 缺页中断)
启动时间 从 642.26ms 降低到 519.45ms (冷启动提升了近 19% 的时间)
效果还是挺不错的哦!!!
补充
配置只在方法内回调到Clang插桩回调函数:
-fsanitize-coverage=func,trace-pc-guard