启动优化二进制重排-操作篇

1. 优化前 缺页中断耗时 (第一次安装)
如果有, 请先删除 -fsanitize-coverage=func,trace-pc-guard 配置.
删除app, 清除Xcode缓存 ;
Xcode菜单栏 > Product > Profile (快捷键command+I) , 等待 running 完成;
出现 Instruments 界面, 选择System Trace ;
启动项目, 到第一个界面出现后停止, 等待分析,
启动优化二进制重排-操作篇
文章图片

搜索Main Thread, 选择 Virtu Memory, 查看缺页中断File Backed Page in 次数与时间;
2. 获取启动时加载的所有函数符号
删除app, 在 Xcode Build Settings > Apple Clang - Custom Compiler Flags > Other C Flags
添加 -fsanitize-coverage=func,trace-pc-guard ,
在启动后会出现的第一个界面中添加如下代码:

#import #import //原子队列 static OSQueueHead symboList = OS_ATOMIC_QUEUE_INIT; //定义符号结构体 typedef struct { void * pc; void * next; } SymbolNode; void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) { static uint64_t N; // Counter for the guards. if (start == stop || *start) return; // Initialize only once. printf("[clang] INIT: %p %p\n", start, stop); for (uint32_t *x = start; x < stop; x++) *x = ++N; // Guards should start from 1. }void __sanitizer_cov_trace_pc_guard(uint32_t *guard) { //if (!*guard) return; // Duplicate the guard check.void *PC = __builtin_return_address(0); SymbolNode * node = malloc(sizeof(SymbolNode)); *node = (SymbolNode){PC,NULL}; //入队 // offsetof 用在这里是为了入队添加下一个节点找到 前一个节点next指针的位置 OSAtomicEnqueue(&symboList, node, offsetof(SymbolNode, next)); }void tmpOrderFile() { NSMutableArray * symbolNames = [NSMutableArray array]; while (true) { //offsetof 就是针对某个结构体找到某个属性相对这个结构体的偏移量 SymbolNode * node = OSAtomicDequeue(&symboList, offsetof(SymbolNode, next)); if (node == NULL) break; Dl_info info; dladdr(node->pc, &info); NSString * name = @(info.dli_sname); // 添加 _ BOOL isObjc = [name hasPrefix:@"+["] || [name hasPrefix:@"-["]; NSString * symbolName = isObjc ? name : [@"_" stringByAppendingString:name]; //去重 if (![symbolNames containsObject:symbolName]) { [symbolNames addObject:symbolName]; } }//干掉自己 NSString * thisFunc = [NSString stringWithFormat:@"_%s",__FUNCTION__]; if ([symbolNames containsObject:thisFunc]) { [symbolNames removeObject:thisFunc]; }//取反 NSMutableArray * symbolAry = [NSMutableArray arrayWithArray:[[symbolNames reverseObjectEnumerator] allObjects]]; NSLog(@"[clang] %@",symbolAry); //将结果写入到文件 NSString * funcString = [symbolAry componentsJoinedByString:@"\n"]; NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"lb.order"]; NSData * fileContents = [funcString dataUsingEncoding:NSUTF8StringEncoding]; BOOL result = [[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil]; if (result) { NSLog(@"[clang] %@",filePath); }else{ NSLog(@"[clang] 文件写入出错"); } }

然后在viewDidAppear中调用tmpOrderFile(), (或者在其他事件方法里调用也可以).
在第一个界面出现后 (或者其他事件方法触发并完成后), 下载文件.
启动优化二进制重排-操作篇
文章图片

下载的文件右击"显示包内容", 找到 tmp 文件下的 lb.order 文件, 里面就是启动加载的所有项目符号了.
3. 重排启动符号
将 ld.order 文件拷贝到项目目录下;
在 Build Setting 中搜索 order file, 写入 ld.order 文件路径:
启动优化二进制重排-操作篇
文章图片

重新执行步骤1, 可查看优化后的效果.
查看符号重排顺序 Build Setting 中搜索 link map, 修改 Write Link Map File 为YES, 运行后到 Products同级目录 Intermediates.noindex 下 找到 ..._ios.build 目录下一个 txt 文件, 搜索 # Symbols:, 就是项目编译的符号顺序, 可以与 ld.order 顺序对比一下, 相同则说明有效果.
启动优化二进制重排-操作篇
文章图片

4. 优化后 缺页中断耗时
【启动优化二进制重排-操作篇】启动优化二进制重排-操作篇
文章图片

这个项目规划良好,所以优化空间没有很大.
缺页中断速度提升了 32.44%;总体速度加快46.34ms,提升29.32%。

    推荐阅读