1、App启动简介
APP的启动可以分为2种
冷启动(Cold Launch):从零开始启动APP
热启动(Warm Launch):APP已经在内存中,在后台存活着,再次点击图标启动APP
APP启动时间的优化,主要是针对冷启动进行优化。
通过添加环境变量可以打印出APP的启动时间分析(Edit scheme -> Run -> Arguments)
DYLD_PRINT_STATISTICS设置为1
如果需要更详细的信息,那就将DYLD_PRINT_STATISTICS_DETAILS设置为1
添加DYLD_PRINT_STATISTICS后在启动时会有如下打印:
Total pre-main time: 0.07 milliseconds (100.0%)
dylib loading time: 106.75 milliseconds (135220.3%)
rebase/binding time: 126687488.6 seconds (340990212.4%)
ObjC setup time: 79.56 milliseconds (100784.9%)
initializer time: 101.70 milliseconds (128823.6%)
slowest intializers :
libSystem.B.dylib : 10.93 milliseconds (13850.7%)
libBacktraceRecording.dylib : 6.35 milliseconds (8054.4%)
libc++.1.dylib : 0.27 milliseconds (353.2%)
libobjc.A.dylib : 3.36 milliseconds (4265.1%)
CoreFoundation : 2.39 milliseconds (3031.6%)
libnetwork.dylib : 0.00 milliseconds (8.4%)
Foundation : 1.72 milliseconds (2182.2%)
libMainThreadChecker.dylib : 71.57 milliseconds (90657.0%)
SecurityFoundation : 0.00 milliseconds (3.7%)
libLLVMContainer.dylib : 0.81 milliseconds (1035.0%)
CoreText : 0.02 milliseconds (33.1%)
UniformTypeIdentifiers : 0.01 milliseconds (13.5%)
FileProvider : 0.10 milliseconds (135.4%)
ConstantClasses : 0.00 milliseconds (3.4%)
AddressBookLegacy : 0.01 milliseconds (14.1%)
CoreDuet : 1.50 milliseconds (1901.8%)
CoreRecents : 0.00 milliseconds (2.3%)
CoreML : 0.38 milliseconds (486.5%)
SiriTTS : 0.77 milliseconds (984.9%)
VoiceServices : 0.00 milliseconds (3.4%)
libViewDebuggerSupport.dylib : 0.65 milliseconds (831.3%)
Montreal : 0.01 milliseconds (18.3%)
2、App冷启动
2.1、冷启动过程
APP的冷启动可以概括为3大阶段:dyld阶段、runtime阶段、main阶段
2.2、dyld阶段
dyld(dynamic link editor),Apple的动态链接器,可以用来装载March-O文件(可执行文件、动态库等)
*可执行文件包含代码、依赖信息。
启动App时,dlyd所做的事情有:
1、装载App的可执行文件,同时会递归加载所有依赖的动态库。
2、当dlyd把可执行文件、动态库都装载完毕后,会通知Runtime进行下一步的处理。
2.3、runtime阶段
启动App时,runtime所做的事情有
1、调用mapiamges进行可执行文件内容的解析和处理
2、在load_images中调用call_load_images,调用所有Class和Category的+load方法
3、进行各种Objc结构的初始化(注册Objc类、初始化类对象等等)
4、调用C++静态初始化器和_attribute((constructor))修饰的函数
到此为止,可执行文件和动态库中所有的符号(Class,Protocol,Selector,IMP……)都已按格式成功加载到内存中,被runtime所管理。
2.4、main函数阶段
执行main函数、执行UIApplicaitonMain函数,执行AppDelegate的application:didFinishaLaunchingWithOptions:方法。
2.5、总结
App的启动由dyld主导,将可执行文件加载到内存,顺便加载所有依赖的动态库,并由runtime负责加载成Objc定义的结构,所有初始化工作结束后,dyld就会调用main函数。
接下来就是UIApplicaitonMain函数,AppDelegate的application:didFinishaLaunchingWithOptions:方法。
3、App的启动优化
3.1、dyld阶段
减少动态库、合并一些动态库(定期清理不必要的动态库)
减少Objc类、分类的数量、减少Selector的数量(定期清理不必要的类、分类)
减少C++虚函数的数量
Swift尽量使用struct
3.2、runtime阶段
用+initialize方法和dispatchonce取代所有的_attribute((constructor))、C++静态构造器、ObjC的+load。
3.3、main函数阶段
在不影响用户体验的前提下,尽可能将一些操作延迟,不要全部在finishLaunching方法中,按需加载。