文章目录
前言
启动分为冷启动和热启动,主要区别是内存是否有APP加载的数据,如果所有的数据需从硬盘读取后加载到内存,那就为冷启动。下面主要是关于冷启动方面的优化。
一、冷启动
1.1 性能检测
APP启动分两个阶段来测试:
- main函数前(pre-main)
主要是dyld流程部分,包括动态库加载、类的加载、C++静态对象处理等。通过在Xcode中添加环境变量DYLD_PRINT_STATISTICS为YES
//模拟器数据不真实,仅参考
Total pre-main time: 126687488.8 seconds (0.0%) //总耗时
dylib loading time: 258.93 milliseconds (0.0%) //dyld加载耗时,官方建议自定义动态库不超过6个
rebase/binding time: 126687487.6 seconds (0.0%)//重定址和符号绑定耗时
ObjC setup time: 632.00 milliseconds (0.0%)//OC类注册耗时
initializer time: 366.95 milliseconds (0.0%)//+load、c++构造初始化耗时
slowest intializers : //最慢的初始化器
- main函数后
从main()函数开始至applicationWillFinishLaunching结束,我们统一称为main()函数之后的部分。利用锚点分析applicationWillFinishLaunching的耗时。
1.2 优化
官方建议的启动时间要求:
应该在400ms内完成main()函数之前的加载
整体过程耗时不能超过20秒
,否则系统会kill掉进程,App启动失败
对于main函数前的优化
- 减少OC类,移除不需要的类
- 减少动态库,移除不需要的动态库。可通过动态库合并来让动态库数量不超过6个
- 尽量不要写__attribute__((constructor))的C函数,也尽量不要用到C++的静态对象
- 尽量不要使用+load
- 压缩图片大小,减少I/O操作量
对于main函数后的优化
- 延迟不必要的页面、配置等加载
- 耗时操作考虑多线程异步操作
- 使用二进制重排来减少启动时硬盘到内存的操作次数。
二、二进制重排
二进制重排指的是重排编译阶段的代码文件和函数的顺序。要了解二进制重排需了解虚拟内存,相关知识可参考《深入理解计算机系统》第9章虚拟内存中的内容。
2.1 原理
编译器生成二进制代码时,默认按照链接的.o顺序写文件,按照.o内部顺序写函数,如果函数跨页了,就会触发多次Page Fault,所以把函数排到一个Page里,只需要一次Page Fault。
iOS中页的大小可通过下面代码打印
extern vm_size_t vm_page_size;
NSLog(@"%lx", vm_page_size);
在真机中每页为16KB,模拟器中为4KB。
2.1.1 PageFault检测
通过Instruments
中的Systme Trace
,选择项目,选中main thread,选择Virtual Memory
,查看File Backed Page In(PageFault)
和其他的相关次数、时间等。
2.2 重排
要进行重排要看到二进制数据的顺序,如何进行重排。
2.2.1 二进制符号顺序查看
在Build Settings
中搜索link Map
,设置Write Link Map File为YES
,然后编译,在包
文件中向上两级
找到Intermediates.noindex,进入xxx.build最后找到xxx-LinkMap-normal-x86_64.txt文件,打开找到Symbol可看到按编译时文件和文件内部函数书写顺序排列。
2.2.2 通过.order文件重排
创建xxx.order文件,在Build Settings
中搜索order file
,加入./xxx.order,然后编译。
那xxx.order文件中的内容怎么来,可通过clang插桩hook函数然后保存到xxx.order中。
2.2.3 Clang插桩
官方介绍: https://clang.llvm.org/docs/SanitizerCoverage.html#tracing-pcs
SanitizerCoverage 是 Clang 内置的一个代码覆盖工具,它把一系列以 _sanitizer_cov_trace_pc 为前缀的函数调用插入到用户定义的函数里来实现全局 AOP。其覆盖之广,包含 Swift/Objective-C/C/C++ 等语言,Method/Function/Block 全支持。
使用步骤:
- Build Settings 搜索 Other C Flags,添加-fsanitize-coverage=func, trace-pc-guard参数(OC); Other Swift Flags添加-sanitize-coverage=func 和 -sanitize=undefined(swift)
- 在__sanitizer_cov_trace_pc_guard_init和__sanitizer_cov_trace_pc_guard_init方法中进行相关代码编写或直接使用第三方AppOrderFiles
- 在didFinishLaunchingWithOptions中调用相应的方法生成xxx.order文件并进行调用顺序重排<