6

iOS app启动时间

 3 years ago
source link: https://www.jianshu.com/p/f41bf869809f
Go to the source link to view the article. You can view the picture content, updated content and better typesetting reading experience. If the link is broken, please click the button below to view the snapshot at that time.
neoserver,ios ssh client

iOS app启动时间

应用启动流程

iOS应用启动可以分为pre-main阶段和main()阶段

pre-main阶段
  • 1.1. 加载应用的可执行文件
  • 1.2. 加载动态链接库加载器dyld(dynamic loader)
  • 1.3. dyld递归加载应用所有依赖的dylib(dynamic library 动态链接库)
main()阶段
  • 2.1. dyld调用main()
  • 2.2. 调用UIApplicationMain()
  • 2.3. 调用applicationWillFinishLaunching
  • 2.4. 调用didFinishLaunchingWithOptions
  1. pre-main阶段

对于pre-main阶段,Apple提供了一种测量方法,在 Xcode 中 Edit scheme -> Run -> Auguments 将环境变量DYLD_PRINT_STATISTICS 设为1 。之后控制台会输出类似内容:

Total pre-main time: 217.57 milliseconds (100.0%)
         dylib loading time:  29.38 milliseconds (13.5%)
        rebase/binding time:  12.15 milliseconds (5.5%)
            ObjC setup time:  16.71 milliseconds (7.6%)
           initializer time: 159.09 milliseconds (73.1%)
           slowest intializers :
             libSystem.B.dylib :   4.17 milliseconds (1.9%)
    libMainThreadChecker.dylib :  34.80 milliseconds (15.9%)
          libglInterpose.dylib :  53.05 milliseconds (24.3%)
         libMTLInterpose.dylib :  14.19 milliseconds (6.5%)
                       ZhouDao :  89.54 milliseconds (41.1%)

这样我们可以清晰的看到每个耗时了。

2.main()阶段

mian()阶段主要是测量mian()函数开始执行到didFinishLaunchingWithOptions执行结束的时间,我们直接插入代码就可以了

CFAbsoluteTime StartTime; 
int main(int argc, char * argv[]) { 
StartTime = CFAbsoluteTimeGetCurrent(); 

到主UI框架的.m文件用extern声明全局变量StartTime

extern CFAbsoluteTime StartTime; 

在viewDidAppear函数里,再获取一下当前时间,与StartTime的差值即是main()阶段运行耗时。

double launchTime = (CFAbsoluteTimeGetCurrent() - StartTime); 

[HomeViewController viewDidAppear:] launchTime:0.619898

改善启动时间

pre-main阶段

在这一阶段,我们能做的主要是优化dylib

加载 Dylib

之前提到过加载系统的 dylib 很快,因为有优化。但加载内嵌(embedded)的 dylib 文件很占时间,所以尽可能把多个内嵌 dylib 合并成一个来加载,或者使用 static archive。

使用 dlopen() 来在运行时懒加载是不建议的,这么做可能会带来一些问题,并且总的开销更大。

Rebase/Binding

之前提过 Rebaing 消耗了大量时间在 I/O 上,而在之后的 Binding 就不怎么需要 I/O 了,而是将时间耗费在计算上。所以这两个步骤的耗时是混在一起的。

之前说过可以从查看 __DATA 段中需要修正(fix-up)的指针,所以减少指针数量才会减少这部分工作的耗时。对于 ObjC 来说就是减少 Class,selector 和 category 这些元数据的数量。从编码原则和设计模式之类的理论都会鼓励大家多写精致短小的类和方法,并将每部分方法独立出一个类别,其实这会增加启动时间。对于 C++ 来说需要减少虚方法,因为虚方法会创建 vtable,这也会在 __DATA 段中创建结构。虽然 C++ 虚方法对启动耗时的增加要比 ObjC 元数据要少,但依然不可忽视。

Objc setup

大部分ObjC初始化工作已经在Rebase/Bind阶段做完了,这一步dyld会注册所有声明过的ObjC类,将分类插入到类的方法列表里,再检查每个selector的唯一性。

在这一步倒没什么优化可做的,Rebase/Bind阶段优化好了,这一步的耗时也会减少。

Initializers

到了这一阶段,dyld开始运行程序的初始化函数,调用每个Objc类和分类的+load方法,调用C/C++ 中的构造器函数(用attribute((constructor))修饰的函数),和创建非基本类型的C++静态全局变量。Initializers阶段执行完后,dyld开始调用main()函数。

在这一步,我们可以做的优化有:

  • 1、少在类的+load方法里做事情,尽量把这些事情推迟到+initiailize
  • 2、减少构造器函数个数,在构造器函数里少做些事情
  • 3、减少C++静态全局变量的个数
main()阶段的优化

这一阶段的优化主要是减少didFinishLaunchingWithOptions方法里的工作,在didFinishLaunchingWithOptions方法里,我们会创建应用的window,指定其rootViewController,调用window的makeKeyAndVisible方法让其可见。由于业务需要,我们会初始化各个二方/三方库,设置系统UI风格,检查是否需要显示引导页、是否需要登录、是否有新版本等,由于历史原因,这里的代码容易变得比较庞大,启动耗时难以控制。

所以,满足业务需要的前提下,didFinishLaunchingWithOptions在主线程里做的事情越少越好。在这一步,我们可以做的优化有:

  • 1、梳理各个二方/三方库,找到可以延迟加载的库,做延迟加载处理,比如放到首页控制器的viewDidAppear方法里。
  • 2、梳理业务逻辑,把可以延迟执行的逻辑,做延迟执行处理。比如检查新版本、注册推送通知等逻辑。
  • 3、避免复杂/多余的计算。
  • 4、避免在首页控制器的viewDidLoad和viewWillAppear做太多事情,这2个方法执行完,首页控制器才能显示,部分可以延迟创建的视图应做延迟创建/懒加载处理。
  • 5、首页控制器用纯代码方式来构建。

总结起来,好像启动速度优化就一句话:让系统在启动期间少做一些事。当然我们得先清楚工程里做的哪些事是在启动期间做的、对启动速度的影响有多大,然后case by case地分析工程代码,通过放到子线程、延迟加载、懒加载等方式让系统在启动期间更轻松些。

转自:http://mobile.51cto.com/hot-584384.htm


Recommend

  • 94
    • www.cocoachina.com 6 years ago
    • Cache

    优化 App 的启动时间实践 iOS

  • 44
    • www.cocoachina.com 6 years ago
    • Cache

    【高级iOS】启动时间优化

  • 69
    • www.10tiao.com 6 years ago
    • Cache

    SDK启动时间测试方案

    点击蓝字关注这个神奇的公众号~ 目前笔者主要负责商业广告SDK的测试,需要对接大量的媒体APP,媒体方经常会反应一些性能问题,而好的用户体验与性能表现才能让集成方更加满意,最近有媒体提出在集成SDK的时候,启动...

  • 85
    • www.zoomfeng.com 6 years ago
    • Cache

    iOS启动时间优化 - 第七章

  • 96
    • www.cocoachina.com 6 years ago
    • Cache

    iOS启动时间优化

    本文将针对iOS APP的启动时间优化一波。本次优化从结果上来看,main阶段的优化效果最显著,尤其是启动时的一些IO操作处理,对启动时间的减少有很大作用。

  • 59
    • 掘金 juejin.im 6 years ago
    • Cache

    App启动时间(翻译)

    本文从谷歌官网翻译: developer.android.google.cn/topic/perfo… 用户希望App启够足够快的开始启动,如果一个App启动时间过长,会令用户非常失望,并且可能会在play store中对App评价很低或者干脆卸载我们的Ap

  • 9
    • gsl201600.github.io 4 years ago
    • Cache

    iOS 如何优化 App 的启动耗时

    iOS 的 App 启动时长大概可以这样计算:t(App 总启动时间) = t1(main 调用之前的加载时间) + t2(main 调用之后的加载时间) t1 = 系统 dylib(动态链接库)和自身 App 可执行文...

  • 7

    欢迎访问我的博客原文 当 App 中的业务模块越来越多、越来越复杂,集成了更多的三方库,App 启动也会越来越慢,因此我们希望能在业务扩张的同时,...

  • 4
    • www.jianshu.com 3 years ago
    • Cache

    iOS启动时间优化【转】

    iOS启动时间优化【转】酱油瓶20.6592018.10.18 07:19:01字数 10,810阅读 2,324背景 一个项目做的时间长了,...

  • 8
    • 微信 mp.weixin.qq.com 3 years ago
    • Cache

    如何清除 iOS APP 的启动屏幕缓存

    如何清除 iOS APP 的启动屏幕缓存 Original...

About Joyk


Aggregate valuable and interesting links.
Joyk means Joy of geeK