简单的App启动速度优化

2021-01-13  本文已影响0人  GarrettGao

分析工具:
xCode自带工具 Instrument 的 Timer Profiler。

测试设备:

  1. iPhone6 iOS 12.4.8,这台设备相对来说比较老旧,我们App在次设备上启动速度非常慢,所以效果较明显。
  2. iphone7 iOS 13.4
  3. iPhone11 iOS 14.0.1

测试方式,从点击录制开始启动App,到App启动页面结束点击停止,观察主线程的耗时。

测试启动结果

iPhone6 iOS 12.4.8测试结果:
20210105145004.jpg

可以看到主线程的耗时一共是6.04秒,start占用5.71s,_dyld_start占用327ms(这里需要注意,也因为不是第一次启动,所以dyld二次加载存在直接从缓存中加载,所以耗时比第一次启动会短一些)。

iphone7 iOS 13.4 测试结果:
image.png

主线程的耗时一共是1.57秒,start占用1.50s,_dyld_start占用70ms

iPhone11 iOS 14.0.1 测试结果:
image.png

主线程的耗时一共是754ms,start占用642ms,_dyld_start占用111ms

我们看到最长的时间是iphone6的iOS12系统,6秒的启动时间是我们绝对接受不了的,下面我们看一下在main函数中都是有那些方法调研占用了大多数的时间。

首先我们选择左下脚的 Call Tree 按钮,选择隐藏系统方法,方便我们查看我们自己的方法。

20210105145557.jpg

隐藏系统方能后,只剩下我们代码的方法列表和耗时,但是发现这些方法都是地址,并不是实际解析之后的方法名,如图:


image.png

这里需要注意一下需要DSYM解析成对应的方法名,需要修改一下项目buildSetting的设置,在对应的编译模式下,选择 DWARF with DYSM File

image.png

如果启动过程中有组件的方法,组件通过cocoapod集成的,需要在对应的组件也设置上,可以通过遍历全局设置:

    post_install do |installer|
  installer.pod_target_subprojects.flat_map { |p| p.targets }.each do |t|
    t.build_configurations.each do |config|
        # 设置debug模式,其他模式类似
        config.build_settings['DEBUG_INFORMATION_FORMAT'] = 'dwarf-with-dsym'

    end
  end
end

设置后需要执行一下 pod install,重新把项目run到手机,通过 Time Profiler查看代码耗时:

image.png

可以看到,在启动过程中 有三个计较耗时的方法,启动 HBHRouterManager.regisgerRootVC(vc:)方法耗时达到5.71秒,我们项目这个方法是路由注册处理,调用了全局的类列表并组成对应的Scheme链接映射表,所以比较耗时。所以我们要根据实际情况优化我们耗时的方法,或者调优,或者延后调用,不要堵塞主线程的启动过程。尤其是在 Appdelegateapplication(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool方法中 在return之前,千万不要做特别耗时的工作堵塞主线程。可以尝试在此方法 return之前 sleep(10),那么你的App启动肯定在10秒以上。

我们采用简单方式先处理一下这个耗时的方法:

    // 子线程异步执行注册路由方法,不要堵塞主线程的启动过程
    DispatchQueue.global().async {
        HBHRouterManager.shared.regisgerRootVC(vc: rootViewController)
    }

重新Run,看一下启动耗时:


20210105180544.jpg
image.png

可以看到mainstart调用时间直接降低到了 436ms,App在iPhone6上启动时间从原来的6秒左右降低到739ms。
再看一下剩下的两台机器:

iphone7 iOS 13.4 测试结果:
image.png

主线程的耗时一共是339ms秒,start占用256ms,_dyld_start占用72ms

iPhone11 iOS 14.0.1 测试结果:
image.png

主线程的耗时一共是146ms,start占用38ms,_dyld_start占用108ms

以此类推,其他耗时的方法采用对应的优化方案调优,即可实现最简单的启动速度的优化。

这里只是简单介绍在主线程启动执行时的耗时方法进行优化,不同的启动场景对App的耗时影响也不太一样,苹果给我们例举了几种启动场景:

  1. 重启手机,首次启动App。
  2. 强制退出App,然后启动。
  3. 打开其他App,然后启动你的App。
  4. 使用一个非常大的App(例如,可以使用许多图形资源或实时摄像机输入的App),然后启动您的应用程序。

还列举了其他影响启动速度的因素:

  1. App动态库的数量,直接影响到dyld加载的时间。

  2. 静态库初始化时:

    1. C++静态构造函数。
    2. 在类或者分类中的+load方法。
    3. 标有clang属性 __attribute__((constructor)) 的方法 。
    4. 链接到App或Framework任何函数的__DATA__mod_init_func

关于线上版本App的启动时长统计,苹果也给提供了工具,可以直接查看不通版本的启动耗时:
Xcode -> Window-> Organizer -> Metrics - > Launch Time

App启动时间统计
最后附上官网优化文档:苹果官网启动优化文档
上一篇下一篇

猜你喜欢

热点阅读