IT数码 购物 网址 头条 软件 日历 阅读 图书馆
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
图片批量下载器
↓批量下载图片,美女图库↓
图片自动播放器
↓图片自动播放器↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁
 
   -> 开发工具 -> APP Launch 优化 -> 正文阅读

[开发工具]APP Launch 优化


本文将探讨一下对于APP Launch的相关概念以及影响Launch的因素及优化方法。

Launch

APP Launch的概念是 用户点击APP icon开始,system将APP加载入内存,直到展现APP的第一帧画面位置的过程。这个过程的时间长短,对于用户体验的影响,还是比较重要的。

pre-main vs. post-main

APP Launch过程从代码角度来划分,可以分为pre-main, post-main两个阶段。即,在进入APP main函数前,以及进入APP main函数后,调用Application delegate相关方法两个阶段。

对于iOS APP,WWDC将启动阶段划分为如下图示:

在这里插入图片描述
紫色的部分为在进入main函数前的部分,我们称之为pre-main
绿色为进入main函数,直到APP第一帧渲染出来的时间,
蓝色是为APP首页数据加载完毕并完全显示的时间。
绿色和蓝色的部分我们称之为post-main

pre-main

pre-main,主要包括两部分: System Interface, Runtime Init

System Interface

System Interface主要工作是将APP加载入内存,设置APP可以运行的内存环境。包括

  • 将APP加载入内存

  • Load dylibs
    dyld会递归依次加载动态库入内存中,这其中包括系统通用库,以及我们自己定义或第三方动态库。Apple系统会在操作系统启动时会计算和缓存系统动态库。因此影响这部分时间的,主要是我们自定义或第三方动态库。

  • 符号地址修正
    Apple为了解决安全问题,引入ASLR和Code Sign,如果不作符号修正,程序将没法正常运行,所以会有Rebase和Bind过程。

  • libSystem init
    调用系统的的一些初始化方法,这部分一般时间比较固定,可以不用太关注。

Runtime Init

这个阶段是初始化我们编程语言环境,包括OC及Swift。这个阶段是通过注册dyld的_dyld_objc_notify_register回调,在image加载完时做的。

  • 初始化有默认值的静态变量和全局变量的

  • C++ static constructors.

  • 加载category

  • Objective-C +load methods defined in classes or categories.
    按照继承层级依次调用:父类+load→子类+load→category +load,注意category的+load不会覆盖原类。

  • Functions marked with the clang attribute attribute((constructor)).

  • Any function linked into the __DATA,__mod_init_func section of an app or framework binary.

post-main

经过pre-main阶段后,代码就进入了main()方法体内,这里主要包含三个阶段:

  • UIKit Init
    • 实例化 UIApplication 和 UIApplicationDelegate
    • 开始事件处理和系统集成
  • Application Init
    这部分是我们熟悉的UIApplicationDelegate的几个生命周期调用:
    • application:willFinishLaunchingWithOptions:
    • application:didFinishLaunchingWithOptions:
    • applicationDidBecomeActive:
    • scene:willConnectToSession:options:
    • sceneWillEnterForeground:
    • sceneDidBecomeActive:
  • Initial Frame Render
    这里是App渲染第一帧,主要做了创建、布局和绘制视图的工作,并把准备好的第一帧提交给渲染层渲染。这里面布局计算,图片解码,图层树的递归commit到Render Server等都是可能影响耗时的点,所以要特别注意。

除了上面三个步骤之外,Apple添加了一个蓝色的Extended阶段,这个阶段是指第一帧的UI框架已经加载完毕,我们程序从网络或DB获取数据来初始化UI的过程。这里主要和我们代码如何获取数据的逻辑相关。不同的APP会有不同的实现逻辑,但是对于用户启动APP的感受来说,也是很重要的。

优化方案

我们针对Launch的每个阶段,可以做一些针对性的优化。
pre-main阶段,可以:

  • 尽量使用静态库.a代替动态库.dylib。因为动态库是在运行时动态链接到APP 内存中的,这里就涉及到一些IO操作以及地址定位计算,这些都会消耗Launch 时间。因此可以使用静态库在编译阶段将代码并入最终的APP产物中。
  • 尽量少使用static变量及static 初始化。
  • 使用initialize方法代替+load方法。因为所有的+load方法会在启动时被执行,因此可以使用运行时的initialize方法来优化启动时间。
  • 删除无用代码
    如果符号越多,很显然Rebase和Bind的处理时间就会越长,Objc的初始化也受影响,所以我们需要尽可能减少代码:
  1. 通过逆向二进制或者生成linkmap,解析所有方法(TEXT.text)和引用到的方法(DATA objc_selrefs),找出无用方法删除
  2. 解析所有类(DATA.objc_classlist)和引用到的类(DATA.objc_classrefs),找出无用的类删除
  3. 使用第三方工具或者clang扫描重复代码,精简去重
  4. 使用LLVM_LTO和GCC_OPTIMIZATION_LEVEL等其他编译选项优化二进制大小

post-main阶段,可以:

  • 轻量化Application Delegate中的操作
    主要是针对application(:willFinishLaunchingWithOptions:) 和 application(:didFinishLaunchingWithOptions:) 方法。我们不要在这些方法的main thread中执行一些阻塞的繁重操作,取而代之可以延迟执行或是在子线程中执行。这里可以针对具体情况,做一些优化。
  • 轻量化首屏UI及数据
    首屏尽量不要使用复杂的UI展示,同时对于展示数据,我们可以通过缓存及分段加载的方式,来优化数据响应时间

除了上述方法外,也可以通过二进制重排的手段,来减少启动阶段的内存抖动,进而达到优化启动时间的效果。关于二进制重排,我们可以查找其他资料了解一下。

Profile APP Launch

在之前,我们可以通过设置APP的启动环境变量

DYLD_PRINT_STATISTICS = 1

来在控制台打印在main方法前dyld的耗时统计,但是现在由于Apple升级了dyld,这个变量已经不起作用了。
但是我们可以通过Instrument 中的App Launch工具来调试Launch time。
请添加图片描述
点击启动后,APP Launch会经过若干时间的分析,得到如下图所示的统计结果,可以看到各个阶段的可以看到方法调用堆栈等信息:
请添加图片描述
三击某个阶段,即可聚焦于那个阶段,

请添加图片描述
APP Launch的使用方式可以查阅相关帮助文档,这里就不再赘述。

Cold/Warm/Resume

APP的launch过程,本质上是将APP从存储介质加载到内存中并展示出UI,响应用户操作的过程。这里涉及到一个内存调度的策略。我们知道,在内存紧张的情况下,系统会对内存中长期不被使用的部分转回到存储介质中暂存,同时将其他活跃部分置换到内存中来。

按照这个现实,我们的APP在launc时,可以分为三种情况:Cold launch、Warm launch、Resume。
请添加图片描述
如图所示,Cold->Resume的启动速度依次递增。

关于Cold\Warm\Resume的启动时机如下图所示:
请添加图片描述

参考资料

WWDC 2019

  开发工具 最新文章
Postman接口测试之Mock快速入门
ASCII码空格替换查表_最全ASCII码对照表0-2
如何使用 ssh 建立 socks 代理
Typora配合PicGo阿里云图床配置
SoapUI、Jmeter、Postman三种接口测试工具的
github用相对路径显示图片_GitHub 中 readm
Windows编译g2o及其g2o viewer
解决jupyter notebook无法连接/ jupyter连接
Git恢复到之前版本
VScode常用快捷键
上一篇文章      下一篇文章      查看所有文章
加:2021-12-15 18:30:19  更:2021-12-15 18:32:34 
 
开发: C++知识库 Java知识库 JavaScript Python PHP知识库 人工智能 区块链 大数据 移动开发 嵌入式 开发工具 数据结构与算法 开发测试 游戏开发 网络协议 系统运维
教程: HTML教程 CSS教程 JavaScript教程 Go语言教程 JQuery教程 VUE教程 VUE3教程 Bootstrap教程 SQL数据库教程 C语言教程 C++教程 Java教程 Python教程 Python3教程 C#教程
数码: 电脑 笔记本 显卡 显示器 固态硬盘 硬盘 耳机 手机 iphone vivo oppo 小米 华为 单反 装机 图拉丁

360图书馆 购物 三丰科技 阅读网 日历 万年历 2024年11日历 -2024/11/15 14:19:41-

图片自动播放器
↓图片自动播放器↓
TxT小说阅读器
↓语音阅读,小说下载,古典文学↓
一键清除垃圾
↓轻轻一点,清除系统垃圾↓
图片批量下载器
↓批量下载图片,美女图库↓
  网站联系: qq:121756557 email:121756557@qq.com  IT数码