主要讲解APP冷启动的优化
1. APP 启动的分类
冷启动: 从零开始, 点击 APP
加载;
热启动: APP
已经在内存中, 再次点击图标后加载;
我们常说的APP
启动优化主要是针对冷启动;
通过在xcode
中添加环境变量可以打印出启动的时间;
Edit scheme -> Run -> Environment Variables
添加DYLD_PRINT_STATISTICS
值为1
启动后就会打印启动信息;
执行main
函数之前的时间:
Total pre-main time: 567.86 milliseconds (100.0%)
dylib loading time: 153.19 milliseconds (26.9%)
rebase/binding time: 229.51 milliseconds (40.4%)
ObjC setup time: 135.73 milliseconds (23.9%)
initializer time: 49.28 milliseconds (8.6%)
slowest intializers :
libSystem.B.dylib : 6.81 milliseconds (1.1%)
libMainThreadChecker.dylib : 29.43 milliseconds (5.1%)
DYLD_PRINT_STATISTICS
改为DYLD_PRINT_STATISTICS_DETAILS
可以打印更加详细的信息;
2. APP 冷启动经历哪些阶段
点击 APP 图标到加载成功经历大概三个阶段;
-
dyld(dynamic link editor)
阶段:APP
的动态链接器, 用来装载 Mach-O 文件(可执行文件, 动态库等);
1.1 装载APP
的可执行文件, 同时递归加载所有的依赖动态库;
1.2 当可执行文件和动态库都加载完成后, 通知runtime
进行下一步操作;
-
-
runtime
阶段, 请先看下runtime
源码中的ojbc_init
函数;
2.1 调用map_image
对可执行文件内容解析;
2.2 调用load_images
调用所有Class
和Category
的的+load
方法
2.3 各种objc
结构的初始化(注册类, 初始化类对象等);
2.4 至此可执行文件和动态库中的信息(class
,protocol
,SEL
,IMP
)已经按照格式加载到了内存中, 通过runtime
管理;接下来调用main
函数;
-
-
main
函数阶段;
3.1 调用UIApplicationMain
函数
3.2 调用Appdelegate
中application:()didFinishLaunchingWithOptions()
函数;
-
3. 优化启动时间
针对上面的分析APP
启动过程中做了那些操作, 可以优化APP
的启动时间
-
dyld
阶段:
1.1 减少不必要的动态库, 合并一些库;
1.2 减少objc
的类, 分类, 方法的数量;
1.3swift
能用struct
的地方就不要创建类;
-
-
runtime
阶段:
尽量不要在+load
方法中写逻辑,使用+initialize
+dispatch_once
方式替代;
-
-
main
阶段:
3.1 不要将所有的操作都放在didFinishLaunchingWithOptions
中加载, 将一些不影响用户体验的操作延迟加载;
3.2 按需加载; 多个tab
时, 尽量只加载当前tab
的内容;
-
补充
1. runtime 入口的objc_init方法
/***********************************************************************
* _objc_init
* Bootstrap initialization. Registers our image notifier with dyld.
* Called by libSystem BEFORE library initialization time
**********************************************************************/
void _objc_init(void)
{
static bool initialized = false;
if (initialized) return;
initialized = true;
// fixme defer initialization until an objc-using image is found?
environ_init();
tls_init();
static_init();
runtime_init();
exception_init();
cache_init();
_imp_implementationWithBlock_init();
_dyld_objc_notify_register(&map_images, load_images, unmap_image);
#if __OBJC2__
didCallDyldNotifyRegister = true;
#endif
}