App启动优化 - 实践二

2019-10-28  本文已影响0人  WSJay

概要:

  • 什么是启动?
  • 如何测量启动?
  • 使用Instruments分析启动
  • 跟踪启动的进度

一、启动的重要性

二、启动类型

冷启动、热启动、运行之间的区别:

三、启动过程

image.png

这六个过程包含了从系统初始化到App初始化,再到视图创建和布局,若App有需要,还可能会有一个扩展阶段,用于数据的异步加载。

(一)System Interface

第一阶段System Interface的前半部是DYLD3 ,关于DYLD3可以参考资料 App Startup Time: Past, Present, and Future

第一阶段System Interface的后半部是libSystem Init。在App中初始化底层系统组件的时候,现在这主要是系统方面的工作,有固定的消耗。因此我们不需要关注这一部分。

优化建议:

  • 避免链接未使用的框架;
  • 避免在启动期间加载动态库;
    例如:dlopen()、或NSBundle、或load(),因为这样会损失在缓存中建立的那些优势
  • 硬链接所有的依赖;
(二)Static Runtime Initialization

第二阶段是静态运行时初始化,该阶段主要完成以下工作:

一般而言我们的App不应该在这里做任何工作,除非我们的程序中存在静态初始化方法,或者我们链接的框架带来的。通常不建议静态初始化。

优化建议:

  • 暴露框架中的初始化API;
  • 避免使用+[Class load]方法,减少对启动的影响;
  • 使用+[Class initialize]方法延迟静态初始化;
    如果程序中有一个使用静态初始化的框架,则要考虑暴露API来尽早初始化我们的栈。如果必须要使用静态初始化,请考虑将代码移出+[Class load]。因为+load方法在App启动期间总会被调用。我们可以在类中第一次使用方法时来延迟调用。
(三) UIKit Initialization

第三阶段是UIKit初始化,该阶段的工作如下:

该阶段是系统初始化程序UIApplicationUIApplicationDelegate的时候。在大多数情况下,这是系统的工作,设置事件处理和系统的集成。如果我们在子类UIApplication,或者在UIApplicationDelegate初始化程序中做其他工作,仍然会影响这一阶段。

优化建议:

  • 减少在子类UIApplication中工作;
  • 减少在UIApplicationDelegate初始化中的工作;
(四)Application Initialization

第四阶段是App初始化,最重要的东西都在这里,该阶段的工作如下:

这是作为开发者能够对App启动产生重大影响的地方。如果我们的App还没有采用UISceneAPI,或针对iOS 12及更早版本的用户来说,App初始化仍然可以用这些回调方法。

application:willFinishLaunchingWithOptions:
application:didFinishLaunchingWithOptions:

当App展示给用户时,将会进一步调用下面的方法。

applicationDidBecomeActive:

当我们的App没有采用UISceneAPI时,我们应该在application:didFinishLaunchingWithOptions:方法中创建视图控制器。当使用UIScene时,App初始化的工作方式略有不同。我们仍然可以获得application:willFinishLaunchingWithOptions:application:didFinishLaunchingWithOptions:方法,但是当App展示给用户时,我们将获得UISceneDelegate生命周期回调。

scene:willConnectToSession:options:
sceneWillEnterForeground:
sceneDidBecomeActive:

优化建议:

  • 推迟无关的工作;
    但没必要提交你的第一帧,可以通过将其推送到后台队列,或者稍后再完全执行。
  • 在场景之间共享资源;
    如果我们的App采用了UIScene,要确保在场景之间共享资源。这样做是为了减少多次不必要地进行一些工作的开销。
(五) Frame Render

第五阶段是第一帧渲染,这个阶段相对简单,该阶段的工作如下:

loadView 
viewDidLoad 
layoutSubviews

优化建议:

  • 展平视图层次结构和延迟加载视图;
    我们可以减少层次结构中的视图数量来影响次阶段。也可以通过展平视图来减少使用,或延迟加载在启动期间未显示的视图来实现。
  • 优化自动布局的使用;
    查看自动布局,减少正在使用的约束数量;
(六)Extended

第六阶段是扩展,该阶段的工作如下:

这是从我们第一次提交到向用户显示最后帧的App特定时间段。这是当我们加载异步数据时。其实不是每个App都有这个阶段。如果我们App有这个阶段,那么我们的App应该具有交互性和响应性。

优化建议:

  • 利用os_signpost衡量工作;
    当我们的应用确实有这个阶段时,我们需要了解正在发生什么,并且可以通过利用os_signpostApi来标记和衡量在这两个时期发生的工作。

四、如何正确测量启动

(一) 一致性
image.png image.png
(二)在一个干净一致的环境中测试

通过以下方法,可以保证创建一个干净一致的测试环境:

重启设备可以清除不必要的状态,让系统休眠2-3分钟,来清除任何启动时间工作。

减少对网络的依赖。因为网络会引入相当多的差异。

iCloud在后台运行。这回干扰App的启动。

这是为了减少测量期间不必需要的调试代码的开销,并利用编译时优化。

这是因为它们更加一致,因为某些App可能已经在内存中,并且其中一些系统端服务可能已在运行。

(三)用具有代表性数据进行测试
image.png
(四)测试较新和较旧的设备
image.png
(五)使用XCTest测量启动
image.png

在任何给定的时间,iOS设备都处于各种不同的状态和情况下,这可能会在启动时引起很大的差异。因此当我们分析和比较启动结果时,确保我们进行"Apple - To - App le"的比较是至关重要的。因为如果在进行任何更改之前,你的启动结果完全不可预测。我们如何知道自己是否取得了进展呢?使其可预测的第一步是消除这些差异的来源,例如网络干扰,后台进程中的干扰。现在我们意识到这听起来有悖常理,因为这可能会导致启动不能完全代表常规使用。但这没有关系,拥有一致的结果可以评估很好地进展,这一点尤为重要。在Apple中一直只用这种技术,在开发过程中成功检测回归,并缩短启动时间。然后通过使用在实际情况中收集的遥测数据来验证这些性能的改进。

五、如何优化启动

当我们在代码和工具中查看App的启动时,我们应该记住以下三个提示和技巧:

(一)最小化你的工作
(二)优先考虑你的工作
(三)优化你的工作

六、跟踪启动的进度

image.png

七、参考资料

上一篇 下一篇

猜你喜欢

热点阅读