美文网首页
iOS项目启动时间优化

iOS项目启动时间优化

作者: iOS_小胜 | 来源:发表于2020-04-04 21:44 被阅读0次

    背景

    项目功能越来越复杂化,影响到启动时间(主要是感觉自己菜,需要学习)

    APP启动时都干了什么事

    一般情况下,App 的启动分为冷启动和热启动,我们这里说的是优化冷启动时间。

    冷启动是指, App 点击启动前,它的进程不在系统里,需要系统新创建一个进程分配给它启动的情况。这是一次完整的启动过程。

    热启动是指 ,App 在冷启动后用户将 App 退后台,在 App 的进程还在系统里的情况下,用户重新启动进入 App 的过程,这个过程做的事情非常少。

    一般而言,App 的启动时间,指的是从用户点击 App 开始,到用户看到第一个界面之间的时间。总结来说,App 的启动主要包括三个阶段:
    main() 函数执行前;
    main() 函数执行后;
    首屏渲染完成后。

    1.main() 函数执行前

    main() 函数执行前的阶段启动时间通过添加环境变量,可以打印出APP的启动时间分析:

    (Edit scheme -->Run -->Arguments -->Environment Variables)
    添加一项:Name为DYLD_PRINT_STATISTICS,Value为1,然后运行项目查看日志

    Total pre-main time: 348.75 milliseconds (100.0%)
             dylib loading time: 302.06 milliseconds (86.6%)
            rebase/binding time: 126687488.9 seconds (135339814.9%)
                ObjC setup time:  17.65 milliseconds (5.0%)
               initializer time:  50.90 milliseconds (14.5%)
               slowest intializers :
                 libSystem.B.dylib :   5.88 milliseconds (1.6%)
        libMainThreadChecker.dylib :  32.44 milliseconds (9.3%)
    

    在 main() 函数执行前,系统主要会做下面几件事情(对照上面代码看):

    • 加载可执行文件(App 的.o 文件的集合);
    • 加载动态链接库,进行 rebase 指针调整和 bind 符号绑定;
    • Objc 运行时的初始处理,包括 Objc 相关类的注册、category 注册、selector 唯一性检查等;
    • 初始化,包括了执行 +load() 方法、attribute((constructor)) 修饰的函数的调用、创建 C++ 静态全局变量。

    对应的启动速度优化:

    • 减少动态库加载。每个库本身都有依赖关系,苹果公司建议使用更少的动态库,并且建议在使用动态库的数量较多时,尽量将多个动态库进行合并。数量上,苹果公司最多可以支持 6 个非系统动态库合并为一个。
    • 移除没有用到的类或者方法。
    • +load() 方法的内容可以放到首屏渲染完成后再执行,或使用 +initialize() 方法替换掉。因为,在一个 +load() 方法里,进行运行时方法替换操作会带来 4 毫秒的消耗。
    • 控制 C++ 全局变量的数量。
    2.main() 函数执行后启动时间

    main() 函数执行后的阶段,指的是从 main() 函数执行开始,到 appDelegate 的 didFinishLaunchingWithOptions 方法里首屏渲染相关方法执行完成。

    首页的业务代码都是要在这个阶段,也就是首屏渲染前执行的,主要包括了:

    • 首屏初始化所需配置文件的读写操作;
    • 首屏列表大数据的读取;
    • 首屏渲染的大量计算等。

    很多时候,开发者会把各种初始化工作都放到这个阶段执行,导致渲染完成滞后。更加优化的开发方式,应该是从功能上梳理出哪些是首屏渲染必要的初始化功能,哪些是 App 启动必要的初始化功能,而哪些是只需要在对应功能开始使用时才需要初始化的。梳理完之后,将这些初始化功能分别放到合适的阶段进行。例如地图,支付,统计,推送等功能的注册,有些是必须放在appDelegate中注册,有些可以放在首屏渲染完成之后注册,或者有些可以放在子线程注册。

    3.首屏渲染完成后

    首屏渲染后的这个阶段,主要完成的是,非首屏其他业务服务模块的初始化、监听的注册、配置文件的读取等。从函数上来看,这个阶段指的就是截止到 didFinishLaunchingWithOptions 方法作用域内执行首屏渲染之后的所有方法执行完成。
    这个阶段就是从渲染完成时开始,到 didFinishLaunchingWithOptions 方法作用域结束时结束。这个阶段用户已经能够看到 App 的首页信息了,所以优化的优先级排在最后。但是,那些会卡住主线程的方法还是需要最优先处理的,不然还是会影响到用户后面的交互操作。

    功能级别的启动优化

    功能级别的启动优化,就是要从 main() 函数执行后这个阶段下手。
    优化的思路是:main() 函数开始执行后到首屏渲染完成前只处理首屏相关的业务,其他非首屏业务的初始化、监听注册、配置文件读取等都放到首屏渲染完成后去做。

    其他小优化

    • 合并功能相似的类和扩展(Category)
      由于Category的实现原理,和ObjC的动态绑定有很强的关系,实际上类的扩展是比较占用启动时间的。尽量可能合并一些扩展,并不是让你不使用扩展
    • 清理无用的资源图片,压缩较大的资源图片
      推荐使用LSUnusedResources查找无用的资源图片,使用ImageOptim压缩较大的资源图片
    • 优化applicationWillFinishLaunching
      需要在applicationWillFinishLaunching里处理的业务较多时,可以管理起这些任务
      将不需要马上在applicationWillFinishLaunching执行的代码延后执行
    • 优化rootViewController
      rootViewController的加载,适当将某一级的childViewController或subviews延后加载
      如果你的App可能会被后台拉起并冷启动,可考虑不加载rootViewController
    • 不使用xib,直接使用代码加载首页视图
    • NSUserDefaults实际上是在Library文件夹下会生产一个plist文件,如果文件太大的话一次能读取到内存中可能很耗时,如果耗时很大的话需要拆分(需考虑老版本覆盖安装兼容问题)
    • 每次用NSLog方式打印会隐式的创建一个Calendar,因此需要删减启动时各业务方打的log,或者仅仅针对内测版输出log
    • 梳理应用启动时发送的所有网络请求,是否可以统一在异步线程请求

    方法级别启动优化

    检查首屏渲染完成前主线程上的耗时方法,将非刚需的耗时方法滞后或异步执行。耗时较长的方法主要发生在计算大量数据的情况下,例如加载、编辑、存储图片和文件等资源。
    比如+load() 方法,一个耗时 4 毫秒,100 个就是 400 毫秒。ReactiveCocoa 框架每创建一个信号都有 6 毫秒的耗时。这样,稍不注意各种信号的创建就都被放在了首屏渲染完成前,进而导致 App 的启动速度大幅变慢等。

    目前来看,对 App 启动速度的监控,主要有两种手段。

    第一种方法是,定时抓取主线程上的方法调用堆栈,计算一段时间里各个方法的耗时。

    Xcode 工具套件里自带的 Time Profiler ,采用的就是这种方式。开发类似工具成本不高,能够快速开发后集成到你的 App 中,以便在真实环境中进行检查。

    对于定时时间间隔的控制

    • 间隔长:会漏掉某些方法,从而导致检查出来的耗时不精确
    • 间隔短:抓取堆栈这个方法本身调用过多会影响整体耗时,导致结果不准确
    • 定时抓取主线程调用栈的方式精准度不够高,做参考足以
    • 大神得出最合适时间为 0.01 秒,虽然导致许多运行速度快的方法监控误差,对整体耗时影响小

    第二种方法是,对 objc_msgSend 方法进行 hook 来掌握所有方法的执行耗时。

    Hook:在原方法开始执行时换成执行其他指定的方法,或者在原有方法执行前后执行你指定的方法,来达到掌握和改变指定方法的目的。
    hook objc_msgSend 这种方式的优点是非常精确,而缺点是只能针对 Objective-C 的方法。对c方法和block需要借助第三方框架处理,编写维护成本高。

    检查方法耗时的工具

    推荐使用工具SMCallTrace
    友情提示:需要在SMCallTrace.m中打开第54行的注释。

    自主实现时间检测工具

    实现VC耗时检测

    学习笔记,参考多位大神,感谢大神分享!

    未完待续...

    相关文章

      网友评论

          本文标题:iOS项目启动时间优化

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