抖音品质建设 - iOS启动优化《原理篇》

前言启动是 App 给用户的第一印象 , 启动越慢用户流失的概率就越高 , 良好的启动速度是用户体验不可缺少的一环 。启动优化涉及到的知识点非常多面也很广 , 一篇文章难以包含全部 , 所以拆分成两部分:原理和实践 。
本文从基础知识出发 , 先回顾一些核心概念 , 为后续章节做铺垫;接下来介绍 IPA 构建的基本流程 , 以及这个流程里可用于启动优化的点;最后大篇幅讲解 dyld3 的启动 pipeline , 因为启动优化的重点还在运行时 。
基本概念启动的定义启动有两种定义:

  • 广义:点击图标到首页数据加载完毕
  • 狭义:点击图标到 Launch Image 完全消失第一帧
不同产品的业务形态不一样 , 对于抖音来说 , 首页的数据加载完成就是视频的第一帧播放;对其他首页是静态的 App 来说 , Launch Image 消失就是首页数据加载完成 。由于标准很难对齐 , 所以我们一般使用狭义的启动定义:即启动终点为启动图完全消失的第一帧 。
以抖音为例 , 用户感受到的启动时间:
抖音品质建设 - iOS启动优化《原理篇》

文章插图
 
Tips:启动最佳时间是 400ms 以内 , 因为启动动画时长是 400ms 。
这是从用户感知维度定义启动 , 那么代码上如何定义启动呢?Apple 在 MetricKit 中给出了官方计算方式:
  • 起点:进程创建的时间
  • 终点:第一个CA::Transaction::commit()
Tips:CATransaction 是 Core Animation 提供的一种事务机制 , 把一组 UI 上的修改打包 , 一起发给 Render Server 渲染 。
启动的种类根据场景的不同 , 启动可以分为三种:冷启动 , 热启动和回前台 。
  • 冷启动:系统里没有任何进程的缓存信息 , 典型的是重启手机后直接启动 App
  • 热启动:如果把 App 进程杀了 , 然后立刻重新启动 , 这次启动就是热启动 , 因为进程缓存还在
  • 回前台:大多数时候不会被定义为启动 , 因为此时 App 仍然活着 , 只不过处于 suspended 状态
那么 , 线上用户的冷启动多还是热启动多呢?
答案是和产品形态有关系 , 打开频次越高 , 热启动比例就越高 。
mach-OMach-O 是 IOS 可执行文件的格式 , 典型的 Mach-O 是主二进制和动态库 。Mach-O 可以分为三部分:
  • Header
  • Load Commands
  • Data
 
抖音品质建设 - iOS启动优化《原理篇》

文章插图
 
Header 的最开始是 Magic Number , 表示这是一个 Mach-O 文件 , 除此之外还包含一些 Flags , 这些 flags 会影响 Mach-O 的解析 。
Load Commands 存储 Mach-O 的布局信息 , 比如 Segment command 和 Data 中的 Segment/Section 是一一对应的 。除了布局信息之外 , 还包含了依赖的动态库等启动 App 需要的信息 。
Data 部分包含了实际的代码和数据 , Data 被分割成很多个 Segment , 每个 Segment 又被划分成很多个 Section , 分别存放不同类型的数据 。
标准的三个 Segment 是 TEXT , DATA , LINKEDIT , 也支持自定义:
  • TEXT , 代码段 , 只读可执行 , 存储函数的二进制代码(__text) , 常量字符串(__cstring) , Objective C 的类/方法名等信息
  • DATA , 数据段 , 读写 , 存储 Objective C 的字符串(__cfstring) , 以及运行时的元数据:class/protocol/method…
  • LINKEDIT , 启动 App 需要的信息 , 如 bind & rebase 的地址 , 代码签名 , 符号表…
dylddyld 是启动的辅助程序 , 是 in-process 的 , 即启动的时候会把 dyld 加载到进程的地址空间里 , 然后把后续的启动过程交给 dyld 。dyld 主要有两个版本:dyld2 和 dyld3 。
dyld2 是从 iOS 3.1 引入 , 一直持续到 iOS 12 。dyld2 有个比较大的优化是dyld shared cache , 什么是 shared cache 呢?
  • shared cache 就是把系统库(UIKit 等)合成一个大的文件 , 提高加载性能的缓存文件 。
iOS 13 开始 Apple 对三方 App 启用了 dyld3 , dyld3 的最重要的特性就是启动闭包 , 闭包里包含了启动所需要的缓存信息 , 从而提高启动速度 。


推荐阅读