iOS性能---启动优化(1)汇总篇

启动优化(1)汇总篇
启动优化(2)二进制重排

前言

  • WWDC 2016 中首次出现了 App 启动优化的话题,其中提到:

    App 启动最佳速度是400ms以内,因为从点击 App 图标启动,然后 Launch Screen 出现再消失的时间就是400ms;
    App 启动最慢不得大于20s,否则进程会被系统杀死;(启动时间最好以 App 所支持的最低配置设备为准。)

  • APP的启动可以分为2种
    冷启动(Cold Launch):从零开始启动APP
    热启动(Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP
  • APP启动时间的优化,主要是针对冷启动进行优化

监测启动耗时

  • premain阶段
    通过添加环境变量可以打印出APP的启动时间分析(Edit scheme -> Run -> Arguments

    DYLD_PRINT_STATISTICS设置为1 普通打印
    DYLD_PRINT_STATISTICS_DETAILS设置为1 详细打印

  • main函数阶段
    我们可以通过InstrumentsTimeProfile来统计启动时的主要方法耗时,点击左上角红色按钮运行,勾选左下角Call TreeSeparate ThreadHide System Libraries过滤掉系统库可以查看主线程下方法的耗时。

启动流程

  • premian函数之前
    1. dylib loading time

      动态库加载时间,苹果推荐我们动态库不要超过6个,如果大于6个,多个动态库合并。所以减少动态库的使用,有助于优化启动时间。

    2. rebase/binding

      rebase:程序加载到内存中都会随机的分配一个基地址,这个地址我们称之为ASLR,每一个地址都会加上这个ASLR,才是真正在内存中运行的地址。
      binding:应用程序可能会用到外部的符号,比如NSLOG等方法。第一次调用该方法的时候能通过符号去找指针,并绑定。第二次访问的时候就是真正的地址。

    3. Objc setup time

      OC类的注册。在这个过程中主要做了一些耗时的操作
      读取macho data,找到oc相关的信息
      注册oc类的时候,会有一张全局的映射表,里面存储了类名和类映射关系,sel和 imp一些相关的信息。可能还有一些分类。

    4. initializer time

      会执行+load方法,c++构造函数,用时。所以在项目中,我们不要在这些方法里面做一些延迟加载的事情。

启动优化方案

  1. 使Cpu性能最大化,异步处理,在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部都放在didFinishLaunching方法中,
  2. 自定义动态库不要超过6个,可以合并动态库或使用静态库
  3. 清理不必要的类、分类,Swift尽量使用struct,减少C++虚函数数量
    • 使用fui找到没有#import的代码

      //安装 fui 工具 在终端中执行命令
      sudo gem install fui -n /usr/local/bin
      fui usage: https://github.com/dblock/fui
      到工程目录下,执行 fui find 命令,可以找出所有的没有用到的class文件

    • 利用AppCode(收费,用破解版) 检测未使用的代码:菜单栏 -> Code -> Inspect Code

  4. +initialize方法和dispatch_once取代所有的__attribute__((constructor))、C++静态构造器、ObjC的+load
  5. 二进制重排,详见下篇文章 启动优化(2)二进制重排

参考文章

iOS关于启动时间的检测及优化
抖音品质建设 - iOS启动优化《原理篇》
iOS 启动优化 + 监控实践