启动优化二进制重排-操作篇
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%。
推荐阅读
- Hive常见问题汇总
- 注册分销商的骄傲
- 数据库设计与优化
- 如何启动改变
- spring|spring boot项目启动websocket
- Android系统启动之init.rc文件解析过程
- Improve|Improve Nested Conditionals(优化嵌套的条件语句) 面对大量的if-else语句
- 首屏时间,你说你优化了,那你倒是计算出给给我看啊!
- 数据库|SQL行转列方式优化查询性能实践
- #12-UITableView|#12-UITableView 优化方案