iOS冷启动优化思路

一、冷启动

一般而言冷启动的过程为从点击图标到didFinishLaunching 执行完。这个过程分为两个阶段。

  • 1、main()之前,操作系统加载App可执行文件Mach-O到内存,然后执行加载与链接,然后执行到main()。将此阶段定义为T1
  • 2、main()之后,从main()didFinishLaunching 执行完毕。此阶段为T2
  • 3、实际项目中用户真正看到内容还需要经历一段时间。即didFinishLaunching后首页渲染、数据请求、定位、等。将此阶段定义为T3

经过上述3个阶段。试一次从用户使用角度定义的冷启动,T1+T2+T3。中每个阶段都可以进行优化,

二、分析且优化

1、T1

T1 的过程大致为:

  • 加载dyld到App进程,
  • 加载动态库(包括所依赖的缩影动态库)
  • Rebase 内部指针调整。
  • Bind 把指针正确的指向Image外部的内容。通过符号表查找
  • 初始化Objective-C Runtime
  • 其他初始化

image.png mach-o可执行文件再熟悉不过了。结构为

image.png

  • header 头部,包含了可执行的CPU结构,x86 arm64
  • Load commands 加载命令,包含文件的组织结构和在虚拟内存的布局方式
  • Data 数据,包含Load commands中需要的各个段的数据。Section data

Section data 中包含了

  • __TEXT 代码段,只读,包括函数,和只读的字符串,
  • __DATA数据段,读写,包括可读写的全局变量等
  • __LINKEDIT 包含方法金额变量的元数据。以及代码签名等。

方案、减少动态库,objc类、方法、Objc 的+load 在实际项目中T1优化的空间不是很大。+load 可以用+initialize代替。 可以通过查看Mach-O

  • __TEXT:__objc_methname: 中包含了代码中的所有方法
  • __DATA__objc_selrefs 中包含了所有被使用的方法的引用

2、T2

项目中会在didFinishLaunching中执行大量的启动任务。SDK的初始化。优化空间比较大。

image.png 需要瘦身didFinishLaunching。我们通过梳理重新分类,把它们划分归类,哪些早执行,哪些后面执行。并且制定规则,后续迭代也可以遵守。

image.png

3启动项

创建一个启动项管理器,在适当的节点执行启动。要考虑代码简洁,方便阅读。启动项可以复用代码。可以通过在编译时把函数的指针,写入到可执行文件的__DATA 中,运行时再通过__DATA端取出来进行操作。解决了初始化的方法能够覆盖所以启动阶段。此方法参考QTEventBus来实现的。Clang中有section 方法

`__attribute__ ((used, section ("__DATA,__QTEventBus")))`的作用是告诉编译器这个结构体会用到,麻烦写到`__DATA`段中的`__QTEventBus` section里。
复制代码

4、T3

使用闪屏。缓存策略 闪屏 image.png

image.png 展示闪屏的时候构建首页UI。不浪费时间。

5、实际操作

使用objc_cover 来检测。Python脚本运行即可。 获取到了未使用的方法。很多很多。经过排查后优化了部分。 接下来进行启动项的重新优化。先看当前的时间 使用了BLStopwatch 来打印时间

image.png

对比。自己宏定义了一套监听时间的插件。

image.png

appDidFinishLuanch 里面进行拆分。项目使用的是QTEventBusQTAppModule来进行初始化SDK。并且是异步调用。但是所以初始化都集中一起本身就不太合理。 一顿操作后优化到了2秒左右

image.png

猜你喜欢

转载自juejin.im/post/7049968553327329293