iOS App启动优化(四):编译期插桩 && 获取方法符号多线程
iOS App启动优化(五):收集符号 && 生成 Order File函数
没看过前四篇的胖友们不用担忧,在这里直接贴上 demo
的当前主要代码性能
主要作了如下几件事情:优化
block
、一个c函数func()
、一个oc函数-(void)test
、一个Swift
编写的含有类方法swiftTest
的类touchesBegan:withEvent:
方法中调用了-(void)test
,-(void)test
里面把上述方法嵌套调用,最终会打印字符串test
__sanitizer_cov_trace_pc_guard_init
和__sanitizer_cov_trace_pc_guard
启动的相关方法可能在不一样的线程执行,若是咱们用一个数组直接收集这些符号,会出现线程问题。ui
听到多线程问题立马想到锁,可是这里由于锁耗费性能比较多因此不推荐使用。建议使用原子队列解决这个问题。spa
原子队列是栈结构,经过 队列结构 + 原子性 保证顺序。
导入头文件
#import <libkern/OSAtomic.h>
复制代码
启动的时候方法执行,__sanitizer_cov_trace_pc_guard
获取到的 PC
会做为结构体 Node
的成员变量以链表的形式存储下来。
当咱们点击屏幕时,touchesBegan:withEvent:
里面会倒序取出节点,经过节点内的成员变量 pc
生成 Dl_info
,再从 info
中读取方法符号。经过去重判断后插入到方法符号数组arr
的头部,使最终记录的方法执行顺序是正序。
执行一下代码看看
-[ViewController touchesBegan:withEvent:]
里死循环。
断点看汇编
__sanitizer_cov_trace_pc_guard
居然在反复横跳?
文档里说 __sanitizer_cov_trace_pc_guard
会在每一个边缘级别插入,那么每执行一次 while
循环应该算是一次边界!
解决方案: 修改成只 hook
函数, Target -> Build Setting -> Custom Complier Flags -> Other C Flags
修改成 -fsanitize-coverage=func,trace-pc-guard
再次运行代码
这个时候,咱们已经获取到了正确的方法符号。
在当前类添加 load
方法后执行看输出,发现 load
并无被打印。
load
方法调用时插入的 __sanitizer_cov_trace_pc_guard
参数 guard
为0,默认的函数实现会直接return
,致使没法捕获到 load
。
屏蔽掉 __sanitizer_cov_trace_pc_guard
中的 if (!*guard) return;
便可
成功收集到了启动相关的全部方法符号。
咱们看到输出的函数符号里面缺乏了以前声明的函数(test
、func
、swiftTest
)和 block
,这是由于我没有去调用他们。
只有被调用的函数才会被__sanitizer_cov_trace_pc_guard
捕获。
在 viewDidLoad
里面调用一下
c函数
和block
的符号生成 Order File
前还须要对 c函数
和 block
作特殊处理。
在 objc-750
的 order file
看到这两种符号都是如下划线 "_" 开头的。而咱们获取到的是没有下划线的,因此要拼接上去。
生成 Order File
就是把上面加工好的方法符号集合拼接成字符串并写入文件。
记得移除掉点击触发的touchesBegan:withEvent:
的符号。
看一下咱们的 Order File
完美~ 只要把 Order File
放入工程目录并设置好路径,就完完整整的实现了启动优化~
完结撒花~ 🎉🎉🎉🎉🎉🎉
不爱原理,直接开干的胖友们
看优化效果对比的胖友们