iOS启动优化 —— 理论

  • 1. app启动
  • 2. 虚拟内存 & 物理内存
  • 3. 缺页中断(pagefault)
  • 4. 二进制重排

1. app启动

启动的过程一般是指从用户点击app图标开始到AppDelegate 的didFinishLaunching方法执行完成为止,其中,启动也分为冷启动和热启动:

  • 冷启动:第一次打开app或app被杀死后重新打开叫冷启动(走didFinishLaunchWithOptions方法)
  • 热启动:app在后台且存活的状态下,再次打开app叫热启动(不走didFinishLaunchWithOptions方法)

启动优化通常指的是冷启动优化,冷启动一般分为两个部分,

  • main函数之前 :一般叫做pre-main阶段,指的是唤起 App 到 main() 函数执行之前的过程。
  • main函数之后:从main函数 到Appdelegate 的didFinishLaunching方法执行完成为止。

我们可以在 Xcode 中配置环境变量 DYLD_PRINT_STATISTICS来查看pre-main阶段的耗时(Edit Scheme -> Run -> Arguments ->Environment Variables点击+添加环境变量 DYLD_PRINT_STATISTICS),配置之后运行。这里可以看到pre-main阶段一共用了171.53ms

  • dylib loading time(动态库耗时):主要是加载动态库。动态库载入耗时是难以避免的,因为只要有动态库,就会去载入,并且如果动态库有依赖关系的话,就会消耗时间去查找读取。苹果的系统库则有点不一样,因为它已经载入到内存了,已经在共享缓存空间,并且已经做了非常高速的优化,但是我们自定义的动态库则没有优化。所以苹果给我们一个建议就是动态库的个数不要大于6个。如果大于6个,那么尽可能的去进行动态库的合并。
  • rebase/binding time:偏移修正/符号绑定耗时
    • rebase(偏移修正):任何一个app生成的二进制文件,在二进制文件内部所有的方法、函数调用,都有一个地址,这个地址是在当前二进制文件中的偏移地址。每次启动的时候,系统都会随机分配一个ASLR(Address Space Layout Randomization,地址空间布局随机化)地址值(是一个安全机制,会分配一个随机的数值,插入在二进制文件的开头),例如,二进制文件中有一个 test方法,偏移值是0x0001,而随机分配的ASLR是0x1f00,如果想访问test方法,其内存地址(即真实地址)变为 ASLR+偏移值 = 运行时确定的内存地址(即0x1f00+0x0001 = 0x1f01),ASLR+ 偏移值的动作就是rebase。
    • binding:当内部文件使用外部函数的时候,需要通过内部符号绑定之后访问的。在运行时会将真正的地址给符号,绑定就是给符号赋值的过程。绑定都是懒加载绑定。

binding

  • ObjC setup time(OC类注册的耗时):OC类越多,越耗时。这里优化做的主要是去掉废弃的类。
  • initializer time(执行load和构造函数的耗时)。这里优化做的是减少延迟加载的事情,尽量把消耗的部分丢给子线程。

上面的优化都是毫秒级别的,其实真正的优化启动时间大部分都是在做业务逻辑的优化。当app渲染出首频界面的时候,用户就感知到这个app启动完毕了。所以第一个界面出现的时间越早越好,所以在第一个界面可以做一些假的数据,多开启子线程。

2. 虚拟内存 & 物理内存

早期的数据访问是直接通过物理地址访问的,这种方式有以下两个问题:

  • 内存不够用
  • 内存数据的安全问题

以前的内存加载是将一整个应用放到内存条里面。但是一个应用中,只有部分功能是活跃的。所以,为了解决内存不够用的问题,就采用了懒加载的方式,将应用分成一块一块的,之后只需要将进程中活跃的部分放入物理内存,用到哪里就加载哪里,就可以避免物理内存的浪费。
但是这样做代码会有一个问题,那就是不连续了。那么这个问题该怎么解决呢?解决这个问题的关键就是——虚拟内存。

虚拟内存其本质就是一张虚拟地址和物理地址对应关系的映射表。有了虚拟内存之后,应用程序就不需要去考虑物理内存地址,它只需要去找代码的映射表,然后通过虚拟地址就可以得到相对应的物理内存地址。那么为什么要有这个虚拟地址呢?这样做的好处就是让应用程序访问的内存都是连续的。这里通过cpu里面一个硬件MMU(内存管理单元)来翻译地址,尽管MMU的翻译速度很快,但是如果一个字节一个字节对应,那么效率就非常低。所以就把内存分成了一块一块的,一块一块的内存叫做Page。每个操作系统页的大小(pagesize)不一样,在ios系统里面为16k,在mac系统中为4k。
虚拟内存还解决了安全问题。因为有了虚拟内存之后,应用程序都是访问的虚拟地址,而这个虚拟地址不会映射到别的app的物理内存上面。所以无论怎么访问数据,都跳不出系统分配的进程内存空间。这样就做到了进程和进程之间的安全隔离。

3. 缺页中断(pagefault)

当用户在使用app的过程中,如果使用到一个还没被加载到物理内存中的功能,这个时候操作系统就会发生缺页中断。缺页中断会将cpu执行代码的动作中断掉,然后操作系统把这一页的数据加载到物理内存中,哪里有空位放哪里,然后再寻址,进行读取。这样就避免了内存浪费。但是一般手机启动一段时间后,就没有空位了,这个时候,就会进行页面置换。操作系统会通过页面置换算法,覆盖掉不那么活跃的部分。
我们能输入最大的地址是8个G(0Xffffffffffffffff),每个app的虚拟内存,其地址都是从0X00000100000001开始访问,大小是4G固定的.那么前面4个G的空间是干什么用的呢?这个是因为要隔离32位。64位的系统要兼容32位的系统,那么要如何区分64位和32位的系统呢?只要比0X00000100000000大的内存地址数据,那么就是64位的系统,比0X00000100000000小的内存地址数据,那么就是32位的系统。所以每个app的虚拟内存的大小是4G(实际上不会分配到4个G的大小)。
32位和64位指的是cpu的数据吞吐量,也就是数据总线。

4. 二进制重排

当进程访问一个没有加载到内存中的数据的时候,会触发缺页中断(Page Fault)。缺页中断会阻塞进程。此时就需要先加载数据到物理内存,然后再继续访问。这个时间是毫秒时间,本身可以忽略不计。但是这里有个问题,如果同时有大量的缺页异常发生时,就会有影响。冷启动的时候就会有大量的缺页中断,这个是难以避免的。那么这里面有什么可以优化的空间呢?

打开instrument里面的system trace。


运行软件,搜索main,点进去后查看Virtual Memory的数据。

这里看到File Backed Page in这个数据,这个数据代表着pageFault的次数。第一次启动的时候,pageFault次数是1157次,耗时201.73ms。这里整体耗时是249.82ms,也就是说,pageFault占用了大部分的时间。


这里再一次启动,发现pageFault数量明显变少。这是因为这里是热启动,很多数据仍然在物理内存里面,所以不是所有数据都要重新载入的。

那么要如何对pageFault进行优化呢?任何优化都是建立在浪费的基础上,那么缺页中断有没有浪费呢?启动的时候,要加载几千页,那么有可能第一页里面,只有一行代码是启动时刻需要调用的, 在第二页里面只有一个方法是启动时刻需要调用的。但是这2个16k都加载进去了。还有就是把启动要调用的方法,全都排到前面,这样就可以优化pagefault的次数。而要做到这样的优化,就需要二进制重排。
在Build Settings里面打开Write Link Map File。

运行后去工程目录里面打开link Map 文件。这个就是所有方法代码实现的排列顺序。这里的地址是文件里的地址,之后还要做rebase才能得到物理地址。这里的方法是按编译顺序排列的,而同一个File里面的顺序则是按照编写顺序也就是从上到下排列的。

到文件的根目录下创建一个order文件。

在文件里面根据想要的排列顺序排序。

然后到Xcode的Build setting里面,查找order file,输入文件地址。

重新运行后,发现编译的顺序确实按照.order中的顺序重新排列了,并且没有的符号忽略不计了。

那么启动时刻需要用到哪些符号呢?且听下回分解。

iOS启动优化 —— 二进制重排相关推荐

  1. iOS启动优化-二进制重排与Clang插桩

    二进制重排与Clang插桩 背景 优化方案 准备 认识 插件安装 启动优化 操作系统 演进史 进程通信 二进制重排 .Order文件 小节问题 Clang插桩 Clang插桩配置 Clang插桩原理( ...

  2. APP启动优化——二进制重排,从入门到精通

    一 理论介绍 1.1缺页中断 1.2 Linkmap 1.3 看二进制文件布局 二 探索重排方案 静态扫描+运行时trace. 思维方式,自顶向下的思维方式 Clang SanitizerCovera ...

  3. 抖音品质建设 - iOS启动优化《实战篇》

    前言 启动是 App 给用户的第一印象,启动越慢,用户流失的概率就越高,良好的启动速度是用户体验不可缺少的一环.启动优化涉及到的知识点非常多,面也很广,一篇文章难以包含全部,所以拆分成两部分:原理和实 ...

  4. iOS 启动优化和安装包瘦身

    iOS 启动优化和安装包瘦身 1 启动优化 在iPhone的启动方式中,分为冷启动和热启动两种方式: 1.冷启动(Cold Launch):从零开始启动APP ,需要系统新创建一个进程进行启动,这是一 ...

  5. iOS启动优化之——如何使用Xcode Log、App Launch、代码来计算启动时间 Launch Time

    在iOS启动优化之--如何使用MetricKit 来计算启动时间 Launch Time ,我们提到,可以使用MetricKit 在Organizer中或者直接代码统计,那么还能用什么来统计呢? 配置 ...

  6. iOS 性能优化-启动优化、main函数之前优化-二进制重排

    一个app的启动时间,很大程度会影响用户的体验,所以能优化还是尽量优化的.之前我们已经探究过dyld加载的流程,启动流程分为main函数之前和main函数之后.这里主要做main函数之前的优化建议. ...

  7. iOS启动优化(一)

    1.启动优化 我们的App如果启动时间过长,会出现白屏的问题.在我们App中,我们一般会集成很多的功能,在启动时,会加载很多的组件以及初始化,这样耗费的时间越多,白屏时间就会越长,用户体验相对来说就会 ...

  8. 抖音品质建设 - iOS启动优化之原理篇

    前言 启动是 App 给用户的第一印象,启动越慢用户流失的概率就越高,良好的启动速度是用户体验不可缺少的一环.启动优化涉及到的知识点非常多面也很广,一篇文章难以包含全部,所以拆分成两部分:原理和实战. ...

  9. iOS启动优化/耗电优化

    一.启动优化 1.pre-main阶段 我们可以通过苹果提供了XCode内建的测量方法, 1.点击项目名称 2.Edit scheme... 3.左侧Run 4.中间顶部菜单Auguments 5.在 ...

最新文章

  1. .NetCore~框架版本号不同引起dotnet不能run它
  2. My1stServlet
  3. Javascript如何改变数组的长度?
  4. 杭电 hdu 2040
  5. Linux系统详解 第五篇:Linux的安装-4:Fedora 16的安装
  6. 监听 html dom 变化,js怎么监听元素属性变化
  7. winform 防止多開
  8. php smarty配置文件,Smarty配置文件
  9. 服务器经过交换机传递文件丢失,H3C交换机bin文件丢失后补救方案
  10. 推荐几个阿里、腾讯、美团大佬的公众号
  11. ai智能和大数据测试_测试版可帮助您根据自己的条件创建数据和AI平台
  12. TCP/IP 三次握手
  13. Linux chmod权限详解
  14. 计算机屏保后无法再次启动,电脑开机一直停留在屏保 电脑问题的原因以及解决方法...
  15. Windows消息钩子[键盘监控]
  16. win10无法连接wifi_更新WIN10 1903遇到旧版高通驱动无法连接WIFI重新安装网卡驱动...
  17. 苹果唯冠商标战对iPad3的影响:iPad3太TM贵,肾都不够卖了!
  18. dna计算机ppt模板,七、DNA与蛋白质序列同源分析(进化树构建).ppt
  19. 利用HttpWebRequest自动抓取51la统计数据
  20. vlan是什么?如何划分vlan?如何实现vlan?使用vlan的优点!

热门文章

  1. 皮肤晒黑了怎么快速变白,最好实用的?
  2. 用订阅工具学习英语吧
  3. 名帖178 苏轼 行书《落花诗》
  4. 见证花开!!码上有花
  5. 数字图像处理(第三版,Rafeal C. Gonzalez, Richard E. Woods)--基础
  6. 成本高、落地难、见效慢,开源安全怎么办?
  7. 安卓手机软件批量安装
  8. 奢侈品电商?“寺库”可不是这么定义自己的
  9. 体育课室内计算机教案,【体育健康课教案】_体育与健康室内课教案
  10. OEUF麻雀婴儿床 - 家长寻求新设计的幼儿园