1. 程式人生 > Android開發 >懶人版二進位制重排

懶人版二進位制重排

0. 序言

這是啟動速度提升的第三篇:

  1. 《我是如何讓微博綠洲的啟動速度提升30%的》
  2. 《我是如何讓微博綠洲的啟動速度提升30%的(二)》

第一篇講了動態庫轉靜態庫和二進位制重排帶來的啟動優化以及其原理。

第二篇講了動態庫轉靜態庫到底帶來了哪些改變,以及實踐中遇到的問題應該如何解決。

本篇將介紹懶人版的Clang插樁匯出主工程和三方庫啟動相關的符號表,原理可以參考《我是如何讓微博綠洲的啟動速度提升30%的》

1. YCSymbolTracker

第一篇文章介紹了Clang插樁可以匯出主工程啟動相關的符號表,有朋友問到了如果涉及到CocoaPods匯入的三方庫,該如何進行插樁呢?

最近我把這一塊整理了一下,做了一個CocoaPods的庫

YCSymbolTracker ,下載庫可以得到同款Demo。(覺得不錯的話,可以點一個Star★,biu~)

1.1 匯出主工程啟動相關的符號表

我們一步一步來,首先看一下這個庫如何匯出主工程啟動相關的符號表。

platform :ios,'8.0'
use_frameworks!
target 'Demo' do
  pod 'YCSymbolTracker','~> 0.1.0'
end
複製程式碼

AppDelegate中配置匯出地址:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary
*)launchOptions { self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds]; self.window.rootViewController = [[YCViewController alloc] init]; [self.window makeKeyAndVisible]; [SwiftDemo swiftTestLoad]; NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"demo.order"
]; NSLog(@"%@",filePath); [YCSymbolTracker exportSymbolsWithFilePath:filePath]; return YES; } 複製程式碼

拿到控制檯輸出的地址,開啟檔案:

我們看到了主工程啟動相關的符號表。

1.2 三方庫啟動相關的符號表

我們新增一個三方庫SDWebImage,你也可以嘗試其他庫。

platform :ios,'8.0'
use_frameworks!
target 'Demo' do
  pod 'SDWebImage'
  pod 'YCSymbolTracker','~> 0.1.0'
end
複製程式碼

AppDelegate中新增SDWebImage相關的程式碼:

- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
    self.window.rootViewController = [[YCViewController alloc] init];
    [self.window makeKeyAndVisible];
    [SwiftDemo swiftTestLoad];
    
    [SDWebImageManager.sharedManager cancelAll]; // 新增的程式碼
    
    NSString *filePath = [NSTemporaryDirectory() stringByAppendingPathComponent:@"demo.order"];
    NSLog(@"%@",filePath);
    [YCSymbolTracker exportSymbolsWithFilePath:filePath];
    
    return YES;
}
複製程式碼

我們再匯出一次:

我們發現我們的order檔案沒有發生變化。這是因為我們的Clang插樁只覆蓋了主工程,沒有包括三方庫!

在Pod工程 SDWebImageBuild SettingsOther C Flags-fsanitize-coverage=func,trace-pc-guard 配置。

如果是Swift的三方庫 Other Swift Flags 新增 -sanitize=undefined -sanitize-coverage=func 配置。

這時如果我們直接執行構建的話會報錯。

Undefined symbol: ___sanitizer_cov_trace_pc_guard_init
Undefined symbol: ___sanitizer_cov_trace_pc_guard
複製程式碼

如果看了第一篇文章,或者熟悉這個問題的同學應該馬上就明白了,找不到這個符號。我們的 YCSymbolTracker 庫中其實是有這個符號的,但是由於它們都是動態庫(獨立), SDWebImage 不能直接訪問到 YCSymbolTracker 中的函式。但是我們不能修改三方庫的程式碼,或者修改三方庫的podspec檔案來修改依賴關係。那麼如何讓 SDWebImage 依賴 YCSymbolTracker 從而訪問到這兩個函式呢?

選擇Pods工程的 SDWebImage ,在Frameworks and Libraries中新增 YCSymbolTracker

修改 YCSymbolTracker 是否Embed

這樣我們就為 SDWebImage 添加了 YCSymbolTracker 作為依賴,可以在 Build PhaseDependencies 中驗證:

然後再配置一下Framework Search Path的值${PODS_CONFIGURATION_BUILD_DIR}/YCSymbolTracker

配置好之後我們再跑一次:

嗒噠~現在我們可以看到[SDWebImageManager.sharedManager cancelAll];執行後相關的符號了!也就是說我們拿到了主工程和三方庫啟動相關的符號表了。

2. 懶人版三方庫插樁

主工程和三方庫的插樁匯出符號表的原理我們已經明白了,但是一個工程可能匯入了很多三方庫,我不可能一個一個去弄吧。不用擔心,我提供了懶人指令碼來完成這個事情。

在Podfile最後新增:

post_install do |installer|
    require './Pods/YCSymbolTracker/YCSymbolTracker/symbol_tracker.rb'
    symbol_tracker(installer)
end
複製程式碼

注意: Demo和正式版路徑不太一樣,這裡以正式版的路徑為例。

2.1 動態庫

如果Podfile中採用use_frameworks!,則(幾乎)所有庫是動態庫。

執行完pod install之後就會執行上面的ruby指令碼,指令碼中會完成三方庫的Clang插樁配置和依賴配置。

2.2 靜態庫

如果Podfile中不採用use_frameworks!,則(幾乎)所有庫是靜態庫。

靜態庫我們都知道,會被合併到主工程的Mach-O檔案中,所以可以直接在Pod工程 SDWebImageBuild SettingsOther C Flags-fsanitize-coverage=func,trace-pc-guard 配置,而不會報找不到符號的錯。

執行完pod install之後就會執行上面的ruby指令碼,所以指令碼中沒有新增依賴配置,只新增Clang插樁配置。

2.3 注意事項

匯出order檔案後,就不再需要YCSymbolTracker庫了,刪除之後請重新執行pod install

大專案因啟動相關符號較多,匯出速度可能很慢,請耐心等待。

匯出 綠洲 的啟動符號,我也卡在啟動頁等待了很久,不要著急。


還有什麼問題歡迎大家提出來~ Have FUN~

如果覺得本文對你有所幫助,給我點個贊吧~