App 的启动速度不仅影响我们调试,也直接关系到用户体验。之前有些很久没有打开过的项目,需要花费很长的时间才完成编译;对应的 App 在点击后,许久才出现启动画面。你是否为这些问题苦恼过呢?

这是我观看 WWDC2016 Sessions406 《Optimizing App Start Time》的博客笔记。虽然没有字幕听起来很吃力,但光看 Slide 还是有不少收获的。原文有点长,包括理论是实践两部分,为了方便阅读这里只放出一部分。

Mach-O 文件是如何被加载的

在 mian() 函数执行之前,操作系统为我们做了什么?

exec() -> main()

exec()执行过程:
内核随机分配一段可用的内存给应用程序。但有个规则,即不分配低地址的内存空间,该地址空间大小由处理器的位数决定,情况如下:

  • 32位处理器保留 4K

  • 64位处理器保留 4G

低地址保留,用于保存空指针、异常错误信息等。

加载动态库

内存分配完成后,处理器运行动态加载器(Dynamic loader)来加载动态依赖库(dylibs)。

加载过程:

  1. 映射所有的直接依赖库,递归间接调用的依赖库(Map all dependent dylibs,recurse).

  2. 重建所有的图片(Rebase all images).

  3. 绑定所有图片(Bind all images).

  4. 准备代码层面的加载(ObjC prepare images)

  5. 执行初始化方法(Run initializes).

直接加载:

  • 解析所有的动态库

  • 找出需要的 mach-O 文件

  • 打开并读取文件

  • 认证 mach-O 文件

  • 登记代码签名

  • 为每个 segment 调用 mmap() 映射函数

递归加载:
当所有直接依赖库加载完毕后,还存在直接依赖库依赖于其他库的情况。递归加载间接依赖库,一般 App 需要加载 100 到 400 个动态库!其中绝大多数为系统库,苹果已经最优化了系统库的加载。

2. 重建(Rebasing)

将图片资源根据其地址进行加载,重建信息被编码在 LINKEDIT segment 中。重建的过程按照地址顺序执行,所以可以被内核预取。

3. 绑定(Binding)

应用程序对动态库的引用只是字符层(symbol)面上,绑定过程中需要加载器通过函数名来查找,相对于重建这个过程需要更多的计算。

4. ObjC 准备阶段
  • 完成重建和绑定后的配置工作

  • 登记定义的 ObjC 类

  • 更新实例变量对应的内存位置

  • 分类的方法被插入到主类

5. 初始化(Initializer)
  • 静态分配内存的对象的初始化

  • 调用 +load 方法

  • 调用相关联的动态库

  • 最后,执行 main()函数

启动优化

对于不同的设备启动速度都不相同,苹果认为完美的启动时间是在 400 毫秒以内。App 的最大允许启动时间为20秒,如果超过这个时间就会被 Killed。

我们可以通过编辑工程的 Schemes 来打印 App 的启动中各项时间花费,从而来分析和优化启动过程。
在 Arguments -> Environment Variables 中加入 DYLY_PRINT_STATISTICS

设置后,控制台部分项时间花费输出:

1. 加载动态库

加载动态库需要很大的开销,解决方法是尽可能减少引入不必要的动态库,合并现有可操作的动态库,使用静态文件,使用懒加载等

2. 重建和绑定过程
  • 减少指针变量的使用

  • 减少 Objective-C 类

  • 减少 C++ 虚基类的使用(少见)

  • 建议使用 Swift 结构体

  • 尽可能将属性设置为只读

3. 初始化
  • 将 +load 函数的操作尽可能在 +initialize 方法中执行

  • 简化 C++ 构造函数

  • 不要在初始化方法里面调用 dlopen()

  • 不要在初始化方法里面创建线程

+initialized 会在任何类加载之前被调用,而 +load 是所在类被加载到系统的时候被调用,这通常比 +initialized 调用的时机要早。在 +load 函数里面做操作会延缓系统的启动时间。

dlopen() 函数用于打开 Bundle 尽可能的延迟读取本地的 Bundld 资源,也有利于加快启动速度。

线程的创建需要很大的开销,不要在 App 启动的过程创建子线程。

参考阅读

1. https://developer.apple.com/videos/play/wwdc2016/406/
2. http://objccn.io/issue-6-3/
3. https://code.facebook.com/posts/1675399786008080/optimizing-facebook-for-ios-start-time/

优化 App 的启动速度的更多相关文章

  1. Android性能优化-App启动优化

    原文地址:https://developer.android.com/topic/performance/launch-time.html#common 通常用户期望app响应和加载速度越快越好.一个 ...

  2. 优化 App 的启动时间

    这是一篇 WWDC 2016 Session 406 的学习笔记,从原理到实践讲述了如何优化 App 的启动时间. App 运行理论 main() 执行前发生的事 Mach-O 格式 虚拟内存基础 M ...

  3. Android性能优化-App后台优化

    原文链接 Background Optimizations 前言 后台进程是内存和电池敏感的.一个隐式的broadcast可能会启动很多监听它的后台进程,即使这些进程可能做得工作不多.这可能丢设备性能 ...

  4. 怎样优化app,看Facebook怎样做

    周四,Facebook Engineering blog 发表了一篇名为<Improving Facebook on Android>博文.博文从四个方面(Performance,Data ...

  5. WWDC2018 之 优化 App Assets Optimizing App Assets

    该篇博客记录了观看WWDC Session227<Optimizing App Assets>的内容以及一些理解. 引言 该session主要讲述了使用Assets Catalog的新特性 ...

  6. 如何优化 App 的启动时间

    http://www.cocoachina.com/ios/20161102/17931.html App 运行理论 main() 执行前发生的事 Mach-O 格式 虚拟内存基础 Mach-O 二进 ...

  7. iOS 如何优化 App 的启动时间

    App 运行理论 main() 执行前发生的事 Mach-O 格式 虚拟内存基础 Mach-O 二进制的加载 理论速成 Mach-O 术语 Mach-O 是针对不同运行时可执行文件的文件类型. 文件类 ...

  8. [Android Memory] Android Zipalign zip对齐优化app程序

    转载地址:http://www.cnblogs.com/xirihanlin/archive/2010/04/12/1710164.html 参考文章:http://www.cnblogs.com/l ...

  9. 5个可以帮你优化App的优秀网站

    也许现在有一款App可以提供所有你需要的,你不需要的,或者你可以想象到的内容.但是,有多少App真的可以不仅满足需求而且还能提供很好的用户体验呢? 相信很多APP并没有这样的能力.有一些APP的设计特 ...

随机推荐

  1. Openstack之Swift架构(Cloud Storage)

    Swift是OpenStack的子项目之一,也称为对象储存,适用于储存永久类型的静态数据,例如:虚拟机镜像文件.图片.存档备份等 复制的三个副本如何联系在一起? 让我们用一些具体场景和介绍一些组件,来 ...

  2. HDU 1525 Euclid's Game (博弈)

    Euclid's Game Time Limit: 2000/1000 MS (Java/Others)    Memory Limit: 65536/32768 K (Java/Others)Tot ...

  3. POJ1651Multiplication Puzzle(区间DP)

    比较好做的区间DP 状态转移方程:DP[i][j] 表示区间[i,j]最小的乘积和. DP[i][j] = MIN{DP[i][k-1]+DP[k+1][j] + a[k]*a[i-1]*a[j+1] ...

  4. Max retries exceeded with url

    78 Traceback (most recent call last):   File "thread072413.py", line 163, in <module> ...

  5. jsp页面加载readyState的五种状态根据我们状态添加进度条

    这段代码放在页面最下面 原文如下: document.onreadystatechange = subSomething;//当页面加载状态改变的时候执行这个方法. function subSomet ...

  6. PL/SQL devloper 常用设置

    1)代码自动完成 Tools->Preferences->User Interface->Key Configuration. 找到Tools/Code Assistant,修改为自 ...

  7. Pyqt5.2.1生成的.ui文件转换成.py

    cmd C:\>pyuic5 ui文件路径 -o 要生成的py文件路径 如下: C:\>pyuic5 c:\python33\lib\site-packages\pyqt5\uic\log ...

  8. sql waitfor 延时执行

    看MSDN:http://msdn.microsoft.com/zh-cn/library/ms187331.aspx 语法为: WAITFOR { DELAY 'time_to_pass' | TI ...

  9. UI:UITableView表视图

    表视图 UITableView,iOS中最重要的视图,随处可⻅见. 表视图通常⽤用来管理⼀一组具有相同数据结构的数据. UITableView继承⾃自UIScrollView,所以可以滚动,表视图的每 ...

  10. document.compatMode(判断当前浏览器采用的渲染方式)

    转载自:http://www.cnblogs.com/fullhouse/archive/2012/01/17/2324706.html IE对盒模型的渲染在 Standards Mode和Quirk ...