OC底层原理探索之启动优化

启动之前检测耗时

Main函数之前 pre-main
Main函数之后
其实iOS已经给我们提供了监测Dyld的选项,我们只需要配置下就可以
image.png

运行,控制台输出

image.png

  • dylib loading time: 46.99 milliseconds (206.9%): 动态库载入 苹果建议6个
  • rebase/binding time: 126687488.9 seconds (68758989.5%): 重定位 绑定
  • ObjC setup time: 8.95 milliseconds (39.4%): OC类注册
  • initializer time: 32.13 milliseconds (141.5%): load 构造函数的耗时

前言虚拟地址

早期使用物理内存阶段:
1.安全问题:虚拟内存也解决了安全问题,不能直接操作内存了。
2.内存不够用 => 整个加载到内存条上 => 后面发展:用到才加载懒加载 => 造成内存地址不连续 => 出现了一个映射表(CPU MMU翻译地址)虚拟地址和物理地址一一对应,虚拟地址是连续的 => 内存分页管理page
在iOS一页=16k
在Mac一页=4k
image.png

有了虚拟内存之后,做到了进程和进程之间的安全隔离, 每一个进程都是自己的一块虚拟内存。

image.png
虚拟内存页的大小:4G
缺页异常:在进程1中操作了P4,此时P4只是虚拟内存还没有加载到物理内存,此时会报pageFault缺页异常、缺页中断,CPU中断,操作系统就开始吧P4对应的数据加载到物理内存中。
页面置换:基本上物流内存是没有多余的空位,此时用到了页面置换,系统的置换算法:覆盖掉不那么活跃的部分。

系统为了进程之间的通信:给了专门的接口,保证进程之间的安全(共享缓存)
iPhone6s开始,物理内存的Page大小是16k,6和之前的设备都是4K
32位和64位其实是硬件的区别:CPU数据总线

rebase重定位

由于存在了虚拟内存,那么我们应用程序在物理内存上的加载都是随机的。所以文件中的数据访问都是随机的。每次应用程序启动,内存都是从0开始,所以此时相对应的安全又不存在了。后面出现了ASLR让每次生成的地址不是从0开始,从一个随机的位置开始。内部的文件都会根据ASLR的起始位置偏移一定的量

ASLR + offset:这个动作就叫做rebase重定位

二进制重排

当我们的代码访问到没有被加载到内存的代码时,此时会有缺页中断。虽然是毫秒级别的,但是如果有大量的缺页异常的时候,耗时就存在一定的优化空间,在App冷启动的时候存在大量的缺页异常,这个是必然的。 把启动时刻的方法手动的排到前面,这就叫做二进制重排

  1. 首先在配置里面把Write Link Map File设置为YES

image.png

  1. Build 成功之后,show in finder, 找到二进制文件

image.png
image.png

  1. 打开Libobjc的源码,找到这个libobjc.order文件,这个文件就是决定了编译器执行二进制文件的顺序
  2. 自定义order文件,在该文件的根目录下新增一个order文件,里面都是一些符号

image.png
image.png

  1. 使用

image.png

  1. Bulid 再次打开二进制文件

image.png
我们发现这个执行顺序就是按照自定义order的顺序,如果没有的符号会过滤掉。回到主题,所以我们应该知道在启动时刻调用了哪些方法,才能进行重排。

写在最后-思考

  • 我们可以hook所有的方法,但是无法追踪C函数和block

  • 我们下一篇介绍100%hook到所有的方法和函数-Clang插桩。

© 版权声明
THE END
喜欢就支持一下吧
点赞0 分享