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
放入工程目錄並設置好路徑,就完完整整的實現了啓動優化~
完結撒花~ 🎉🎉🎉🎉🎉🎉
不愛原理,直接開乾的胖友們
看優化效果對比的胖友們