懒人版二进制重排

0. 序言

这是启动速度提高的第三篇:ios

  1. 《我是如何让微博绿洲的启动速度提高30%的》
  2. 《我是如何让微博绿洲的启动速度提高30%的(二)》

第一篇讲了动态库转静态库和二进制重排带来的启动优化以及其原理。git

第二篇讲了动态库转静态库到底带来了哪些改变,以及实践中遇到的问题应该如何解决。github

本篇将介绍懒人版的Clang插桩导出主工程和三方库启动相关的符号表,原理能够参考《我是如何让微博绿洲的启动速度提高30%的》swift

1. YCSymbolTracker

第一篇文章介绍了Clang插桩能够导出主工程启动相关的符号表,有朋友问到了若是涉及到CocoaPods导入的三方库,该如何进行插桩呢?ruby

最近我把这一块整理了一下,作了一个CocoaPods的库 YCSymbolTracker ,下载库能够获得同款Demo。(以为不错的话,能够点一个Star★,biu~)markdown

1.1 导出主工程启动相关的符号表

咱们一步一步来,首先看一下这个库如何导出主工程启动相关的符号表。app

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;
}
复制代码

拿到控制台输出的地址,打开文件:oop

咱们看到了主工程启动相关的符号表。post

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~

若是以为本文对你有所帮助,给我点个赞吧~

相关文章
相关标签/搜索