启动优化(一)
两个阶段main(pre-main)之前、main阶段
一、pre-main阶段时间查看,在xcode里面设置环境变量DYLD_PRINT_STATISTICS,打印时间
**Total pre-main time: 20.71 milliseconds (100.0%)**
**dylib loading time: 44.69 milliseconds (215.7%)**
**rebase/binding time: 126687488.8 seconds (147130233.7%)**
**ObjC setup time: 11.13 milliseconds (53.7%)**
**initializer time: 52.46 milliseconds (253.2%)**
**slowest intializers :**
**libSystem.B.dylib : 3.45 milliseconds (16.6%)**
**libBacktraceRecording.dylib : 7.26 milliseconds (35.0%)**
**libobjc.A.dylib : 0.96 milliseconds (4.6%)**
**CoreFoundation : 0.85 milliseconds (4.1%)**
**libMainThreadChecker.dylib : 38.03 milliseconds (183.6%)**
- 1、dylib链接动态库,苹果官方建议不大于6个,可以合成一个大的库。
- 2、rebase/binding:地址修正/符号绑定(RSLR:地址空间布局随机化,随机偏移值加载再进程的虚拟空间前)
- 3、ObjC setup:OC内容注册(2万个类 约= 0.8秒)
- 4、initializer:load方法加载的时间
优化方案:二进制重排
二、main阶段优化
- 1、类尽量使用懒加载,即不实现load方法
- 2、发挥cpu的价值,多线程初始化
- 3、Xib、Sb会先解析成代码,首个显示的页面别用
三、虚拟内存和物理内存
*某个技术的出现,是为了解决问题,我们通过问题查看本质
1、物理内存我们知道是我们的内存条,那虚拟内存是什么,为什么会有虚拟内存?
*物理内存会存在内存浪费和安全问题
a、计算机早期是没有虚拟内存的,全部都是物理地址,它是将整个进程(应用程序)加载到内存,会造成内存浪费。
b、物理内存是连续的地址,进程加载到内存中是顺序的,所以可以通过地址偏移,拿到其他程序的数据,这样是不安全的。
2、虚拟内存和物理内存关系
虚拟地址 --> 【映射表(页表)】--> 物理内存
进程在运行的时候,会开辟一块虚拟内存,cpu访问数据的时候,通过虚拟地址(寻址),根据系统管理的页表,(CPU的MMU(CPU的一个硬件),即内存管理单元,找到物理地址)转换成物理地址(地址翻译)。这样就无法访问其他进程的数据。(解决安全问题)
3、内存分页管理(内存使用率,效率问题,解决内存浪费问题)
1、以页为单位,而不是字节,如果映射表以字节为单位,那就占用了很大,
终端:PAGESIZE
mac os、linux 一页4kb 4096字节/ ios一页 16kb
1、页面是有分0和1的,0表示无数据,当前数据不在物理内存中。
2、整个应用程序加载的时候,并不会把应用的所有数据放到内存中,只会放用到的部分。
3、如果发现为P2为0,会出现页中断,缺页异常,操作系统会发出的异常,操作系统阻塞当前进程,将磁盘对应的P2的数据加载到物理内存,将虚拟内存指向物理内存。
进程虚拟页表
| 1 | P1 |
|---|---|
| 0 | P2 |
| 1 | P3 |
| 1 | P4 |
4、内存是一页页加载的,所以不够用时,会根据页面置换算法,覆盖不活跃的页面,保证当前进程正常运行,所以内存永远够用。
4、新问题:进程加载到虚拟内存时,都是从0xf0000开始的,(通过地址访问函数)所以是不安全的,代码hook,很容易被静态注入,所以衍生出了ASLR。虚拟内存加载前,加个偏移值。
5、二进制重排,缺页异常,因为代码在mach.o中的位置是根据文件的顺序生成的(编译的顺序),所以加载到虚拟内存中不都是1
ios页中断时
1、数据加载到磁盘,磁盘加载到物理内存,将虚拟内存指向物理内存。
2、加载某一页的时候,还会对某一页做签名验证。