美文网首页
iOS启动优化

iOS启动优化

作者: 土豆赶着鸡 | 来源:发表于2019-01-16 16:10 被阅读0次

    想做app启动优化,当然是先了解app启动,什么时候开始?什么时候结束?哪里是我们可以去优化的地方?

    app启动开始:加载应用的可执行文件Mach-O

    app启动结束:调用didFinishLaunchingWithOptions

    Mach-O 可执行文件

    • app启动这里我分成两个阶段:pre-main阶段和main()阶段
    pre-main阶段

    1.加载应用的可执行文件Mach-O

    2.加载动态链接库加载器dyld(dynamic loader)

    3.dyld递归加载应用所有依赖的dylib (dynamic library动态链接库)

    main()阶段

    1.dyld调用main()

    2.调用UIApplicationMain()

    3.调用applicationWillFinishLaunching

    4.调用didFinishLaunchingWithOptions

    好了,任务分好了,开始干活!!!

    注:优化时间=优化前时间-优化后时间

    //下面使用模拟器,建议使用真机+release+冷启动,得到数据才最真实

    一.pre-main阶段

    屏幕快照 2019-01-16 下午1.59.12.png

    在 Xcode 中 Edit scheme -> Run -> Arguments 将环境变量DYLD_PRINT_STATISTICS 设为1 ,打钩

    屏幕快照 2019-01-16 下午2.05.25.png

    根据官方给的四个time,我们可以分为四个步骤

    • 1.load dylibs

    这一阶段dyld会分析应用依赖的dylib,找到其mach-o文件,打开和读取这些文件并验证其有效性,递归加载所有依赖库。

    一般情况下,iOS应用会加载几百个dylibs,其中大部分是系统库,这部分对dylib的加载做了缓存操作。

    所以,依赖的dylib越少越好,我们可以优化的地方:

    1.尽可能减少依赖的dylib的数量
    2.使用开销较小的dylib

    • 2.rebase/bind

    在dylib的加载过程中,系统为了安全考虑,引入了ASLR(Address Space Layout Randomization)技术和代码签名。由于ASLR的存在,镜像(Image,包括可执行文件、dylib和bundle)会在随机的地址上加载,和之前指针指向的地址(preferred_address)会有一个偏差(slide),dyld需要修正这个偏差,来指向正确的地址。

    Rebase在前,Bind在后,Rebase做的是将镜像读入内存,修正镜像内部的指针,性能消耗主要在IO。Bind做的是查询符号表,设置指向镜像外部的指针,性能消耗主要在CPU计算。

    所以,指针数量越少越好,我们可以做的优化有:

    1.减少类Class、方法selector、分类category的数量
    2.减少C++虚函数的的数量(创建虚函数表有开销)
    3.使用Swift structs(内部做了优化,符号数量更少)

    • 3.Objc setup

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

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

    • 4.Initializers

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

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

    1.少在类的+load方法里做事情,尽量把这些事情推迟到+initiailize

    2.减少构造器函数个数,在构造器函数里少做些事情

    3.减少C++静态全局变量的个数

    二.main()阶段

    屏幕快照 2019-01-16 下午3.24.51.png 屏幕快照 2019-01-16 下午3.29.58.png

    在mian.m和AppDelegate.m中加上以上代码,可以获得main()之后启动时间

    这个阶段牵扯到我们的业务,功能的实现

    • 参考个人项目:在didFinishLaunchingWithOptions方法中
      是否显示引导页、是否需要登录、新版本的检测、注册推送、网络状态的检测、三方库的配置和初始化等
      首页控制器的加载,Tabbar和Nav控制器的加载等

    根据个人经验做出一些优化建议:

    这一阶段的优化主要是减少didFinishLaunchingWithOptions方法里的时间,所以我们要确认每个任务的时间量(利用CFAbsoluteTimeGetCurrent()方法去计算,计算方法参考上面),然后找出影响大的去做优化(当然时间容许全部优化最好)

    1.满足业务前提下,didFinishLaunchingWithOptions在主线程里做的事情越少越好

    • 将三方库和一些功能延迟执行,比如放在首页的viewDidAppear方法中

    • 将三方库和一些功能异步执行,比如异步检测新版本的更新,注册推送

    • 避免多余复杂的计算,比如合适的算法减少运算量和内存消耗

    • 采用性能好的API,轻量级的对象

    • 首页控制器用纯代码方式来构建

    相关文章

      网友评论

          本文标题:iOS启动优化

          本文链接:https://www.haomeiwen.com/subject/wjnpdqtx.html