700字范文,内容丰富有趣,生活中的好帮手!
700字范文 > iOS 性能优化-启动优化 main函数之前优化-二进制重排

iOS 性能优化-启动优化 main函数之前优化-二进制重排

时间:2023-07-22 03:15:14

相关推荐

iOS 性能优化-启动优化 main函数之前优化-二进制重排

一个app的启动时间,很大程度会影响用户的体验,所以能优化还是尽量优化的。之前我们已经探究过dyld加载的流程,启动流程分为main函数之前和main函数之后。这里主要做main函数之前的优化建议。

时间检测

我们可以设置环境变量DYLD_PRINT_STATISTICS来检测,这样可以查看main函数前的打印时间。

dylib loading time:加载动态库rebase/binding time: ASLR随机生成一个地址,重新绑定地址/映射ObjC setup time:OC类的注册initializer time:load方法的加载

如果想查看详情的话,还可以设置成DYLD_PRINT_STATISTICS_DETAILS,这样就可以查看详情。

total time: 2.1 seconds (100.0%)total images loaded: 334 (327 from dyld shared cache)total segments mapped: 21, into 354 pagestotal images loading time: 1.9 seconds (90.7%)total load time in ObjC: 11.25 milliseconds (0.5%)total debugger pause time: 1.8 seconds (89.0%)total dtrace DOF registration time: 0.15 milliseconds (0.0%)total rebase fixups: 18,359total rebase fixups time: 1.59 milliseconds (0.0%)total binding fixups: 460,146total binding fixups time: 147.37 milliseconds (6.9%)total weak binding fixups time: 0.01 milliseconds (0.0%)total redo shared cached bindings time: 159.67 milliseconds (7.5%)total bindings lazily fixed up: 0 of 0total time in initializers and ObjC +load: 35.24 milliseconds (1.6%)libSystem.B.dylib : 4.84 milliseconds (0.2%)libBacktraceRecording.dylib : 5.04 milliseconds (0.2%)libMainThreadChecker.dylib : 19.82 milliseconds (0.9%)total symbol trie searches: 1115796total symbol table binary searches: 0total images defining weak symbols: 37total images using weak symbols: 92

可以优化的地方

减少oc类的数量,这里优化的特别微小,微小到忽略不计二进制重排,将系统启动所需的地址放在前几张映射表中,后面会详细讲解减少动态库数量,load方法如果不是不得不,尽量使用initialize和dispatch_once代替

物理内存和虚拟内存

要讲二进制重排,那么我首先得明白什么是虚拟内存,什么是物理内存。下图表示的非常清楚。

一个进程加载时,会产生一个映射表(不仅仅是一张,Mac OSlinux内存4kb一页,iOS16kb一页),通过映射表映射到磁盘中真实的地址,CPU寻址是 通过映射表 找到物理地址。

p1、p2根据编译顺序加载到虚拟也表中,前面的1为用到的,0为暂时未用到的,所以就会有浪费,未加载的也放在前几张表中了,影响加载的时间。

二进制重排

二进制重排的作用就是将启动时所需要的内容放在前几张表中,表越少,加载越快。

这里运用clang静态插桩技术获取方法的符号,大致参考clang官网。

clang配置

在build-setting中Other C Flags配置-fsanitize-coverage=func,trace-pc-guard,如果有swift混编的话,需要额外的配置-sanitize-coverage=func和-sanitize=undefined

获取符号表

__sanitizer_cov_trace_pc_guard和__sanitizer_cov_trace_pc_guard_init为clang官网提供的方法,可以在每个方法调用的时候触发,在这里我们使用队列获取各个方法并存储

#import <dlfcn.h>#import <libkern/OSAtomic.h>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("INIT: %p %p\n", start, stop);for (uint32_t *x = start; x < stop; x++)*x = ++N; // Guards should start from 1.}//原子队列static OSQueueHead symbolList = OS_ATOMIC_QUEUE_INIT;//定义符号结构体typedef struct {void *pc;void *next;}SYNode;void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {void *PC = __builtin_return_address(0);SYNode *node = malloc(sizeof(SYNode));*node = (SYNode){PC,NULL};//进入OSAtomicEnqueue(&symbolList, node, offsetof(SYNode, next));}

在合适的地方,比如开屏页加载完去获取符号,我们这里在touchesBegan方法中获取,并生成order文件

-(void)touchesBegan:(NSSet<UITouch *> *)touches withEvent:(UIEvent *)event{NSMutableArray <NSString *> * symbolNames = [NSMutableArray array];while (YES) {SYNode * node = OSAtomicDequeue(&symbolList, offsetof(SYNode, 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];[symbolNames addObject:symbolName];}//取反NSEnumerator * emt = [symbolNames reverseObjectEnumerator];//去重NSMutableArray<NSString *> *funcs = [NSMutableArray arrayWithCapacity:symbolNames.count];NSString * name;while (name = [emt nextObject]) {if (![funcs containsObject:name]) {[funcs addObject:name];}}//干掉自己![funcs removeObject:[NSString stringWithFormat:@"%s",__FUNCTION__]];//将数组变成字符串NSString * funcStr = [funcs componentsJoinedByString:@"\n"];NSString * filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"fffff.order"];NSData * fileContents = [funcStr dataUsingEncoding:NSUTF8StringEncoding];[[NSFileManager defaultManager] createFileAtPath:filePath contents:fileContents attributes:nil];NSLog(@"%@",funcStr);}

这边拼接的符号什么的是参考系统自己生成的order,打开这个设置,build一下项目,

生成的项目中,在finder中显示,在上上层Intermediates.noindex中,最终找到一个txt文件,里面就有符号表的样式

在这个txt文件中红色内容就是符号。

配置order文件

将我们自己生成的order文件放在根目录中(跟你的pod文件在一层),在link中配置路径,大功告成。

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。