iOS App的启动与优化
App的启动流程App启动分为冷启动和热启动
[*]冷启动:从0开始启动App
[*]热启动:App已经在内存中,但是背景还挂着,再次点击图标启动App。
https://i-blog.csdnimg.cn/direct/308a8506ffbf4aa2ab779363fefc1a37.png
一样寻常对App启动的优化都是针对冷启动。
App冷启动可分为三个阶段:
[*]dyld:加载镜像、动态库
[*]RunTime方法
[*]main函数初始化
动态库vs静态库
静态库:一堆.o文件的聚集(通常是.a后缀),还没有被链接过,缺点是产物体积比力大,长处是链接到App之后体积比力小。
动态库:一个已经链接完全的镜像,长处是产物体积比力小,缺点是链接到App之后体积比力大。
两者最大的区别就是静态库没有被链接过,而动态库被链接过。
一.dyld
dyld是app的动态链接器。重要可以用来装载Mach-O文件(可实行文件、动态库等)
启动APP时,dyld所做的事故有:
https://i-blog.csdnimg.cn/direct/8ff1911c54cd41f0ba70a762466cc2ef.png
加载过程从exec()函数开始,这是一个体系调用。利用体系起首为历程分配一段内存空间。然后实行以下利用:
[*]1.把App的可实行文件加载到内存
[*]2.把dyld加载到内存
[*]3.dyld举办法态链接
具体内容:
[*]1、加载动态库
[*]Dyld从主实行文件的header获取到须要加载的所依靠动态库列表,然后它须要找到每个 dylib,而应用所依靠的 dylib 文件大概会再依靠其他 dylib,以是所须要加载的是动态库列表一个递归依靠的聚集
[*]2、Rebase和Binding
[*]1、Rebase(偏移修正) 任何一个app天生的二进制文件,在二进制文件内部全部的方法、函数调用,都有一个地点,这个地点是在当前二进制文件中的偏移地点。一旦在运行时候(即运行到内存中),每次体系都会随机分配一个ASLR(Address Space Layout Randomization,地点空间布局随机化)地点值(是一个安全机制,会分配一个随机的数值,插入在二进制文件的开头),比方,二进制文件中有一个 test方法,偏移值是0x0001,而随机分配的ASLR是0x1f00,如果想访问test方法,其内存地点(即真实地点)变为 ASLR+偏移值 = 运行时确定的内存地点(即0x1f00+0x0001 = 0x1f01)
[*]2、Binding(绑定) 比方NSLog方法,在编译时期天生的mach-o文件中,会创建一个符号!NSLog(现在指向一个随机的地点),然后在运行时(从磁盘加载到内存中,是一个镜像文件),会将真正的地点给符号(即在内存中将地点与符号举行绑定,是dyld做的,也称为动态库符号绑定),一句话概括:绑定就是给符号赋值的过程
二.RunTime阶段
dyld阶段竣事之后就进入RunTime阶段,这个阶段重要举行如下内容:
1、Objc setup
[*]1、注册Objc类 (class registration)
[*]2、把category的界说插入方法列表 (category registration)
[*]3、包管每一个selector唯一 (selector uniquing)
2、Initializers
[*]1、Objc的+load()函数
[*]2、C++的构造函数属性函数
[*]3、非根本范例的C++静态全局变量的创建(通常是类或布局体)
三.main()函数初始化
App的启动由dyld主导,把可实行文件加载到内存,而且加载全部依靠的动态库,并由RunTime负责加载成objc界说的布局,全部初始化工作竣过后,dyld就会调用mainn函数 接下来就是UIApplicationMain函数,AppDelegate的application:didFinishLaunchingWithOptions:方法
这个内里每每是最占用启动时间的地方,同时也是我们最为可控的地方。
• 进入 main() 函数,启动应用。
• 实行 UIApplicationMain() 函数,创建 UIApplication 对象并设置 AppDelegate。
• 加载应用的主 UI,包罗 storyboard 或 xib 文件,以及 AppDelegate 的各种生命周期方法,如 application:didFinishLaunchingWithOptions:。
四.首屏渲染阶段
初始化rootViewController,加载和渲染界面
渲染完成后,用户将看到应用的首屏。
App冷启动流程总结:
1. dyld 加载阶段:
• 动态链接器 dyld 负责加载应用的可实行文件及其依靠的动态库。此时,体系将会做如下工作:
• 查找应用的可实行文件和动态库
• 将它们加载到内存中
• 举行符号剖析和绑定
• 实行初始化函数(如 +load 方法和静态构造函数)
2. runtime 初始化阶段:
• ObjC 运行时对类和分类举行注册。
• 实行各类 +load 方法,这个阶段还会举行一些 Swift 类的初始化。
3. main() 函数实行阶段:
• 进入 main() 函数,启动应用。
• 实行 UIApplicationMain() 函数,创建 UIApplication 对象并设置 AppDelegate。
• 加载应用的主 UI,包罗 storyboard 或 xib 文件,以及 AppDelegate 的各种生命周期方法,如 application:didFinishLaunchingWithOptions:。
4. 首屏渲染阶段:
• 初始化 rootViewController,加载和渲染界面。
• 渲染完成后,用户将看到应用的首屏。
+load与+initialize
1、+load
(1)+load方法是肯定会在runtime中被调用的。只要类被添加到runtime中了,就会调用+load方法,因此+load方法总是在main函数之前调用。
(2)+load方法不会覆盖。也就是说,如果子类实现了+load方法,那么会先调用父类的+load方法(无需手动调用super),然后又去实行子类的+load方法。
(3)+load方法只会调用一次。
(4)+load方法实行次序是:类 -> 子类 ->分类。而差别分类之间的实行次序不肯定,依据在Compile Sources中出现的次序(先编译,则先调用,列表中在下方的为“先”)。
(5)+load方法是函数指针调用,即遍历类中的方法列表,直接根据函数地点调用。如果子类没有实现+load方法,子类也不会自动调用父类的+load方法。
2、+initialize
(1)+initialize方法是在类或它的子类收到第一条消息之前被调用的,这里所指的消息包罗实例方法和类方法的调用。因此+initialize方法总是在main函数之后调用。
(2)+initialize方法只会调用一次。
(3)+initialize方法实际上是一种惰性调用,如果一个类不停没被用到,那它的+initialize方法也不会被调用,这一点有利于节流资源。
(4)+initialize方法会覆盖。如果子类实现了+initialize方法,就不会实行父类的了,直接实行子类自己的。如果分类实现了+initialize方法,也不会再实行主类的。
(5)+initialize方法的实行覆盖次序是:分类 -> 子类 ->类。且只会有一个+initialize方法被实行。
(6)+initialize方法是发送消息(objc_msgSend()),如果子类没有实现+initialize方法,也会自动调用其父类的+initialize方法。
3、两者的异同
(1)类似点
[*]load和initialize会被自动调用,不能手动调用它们。
[*]子类实现了load和initialize的话,会隐式调用父类的load和initialize方法。
[*]load和initialize方法内部使用了锁,因此它们是线程安全的。
(2)差别点
[*]调用次序差别,以main函数为分界,+load方法在main函数之前实行,+initialize在main函数之后实行。(存疑)
[*]子类中没有实现+load方法的话,子类不会调用父类的+load方法;而子类如果没有实现+initialize方法的话,也会自动调用父类的+initialize方法。
[*]+load方法是在类被装在进来的时间就会调用,+initialize在第一次给某个类发送消息时调用(好比实例化一个对象),而且只会调用一次,是懒加载模式,如果这个类不停没有使用,就不回调用到+initialize方法。
4、使用场景
(1)+load一样寻常是用来互换方法,由于它是线程安全的,而且肯定会调用且只会调用一次,通常在使用UrlRouter的时间注册类的时间也在+load方法中注册。
(2)+initialize方法重要用来对一些不方便在编译期初始化的对象举行赋值,大概说对一些静态常量举行初始化利用。
冷启动时间优化
1.镌汰动态库(dyld阶段)
一样寻常不多于6个,多余须要举行归并,动态库越多,dyld阶段加载时间越长。
2.镌汰类和方法的数量
3.延长初始化(rebase/Binging阶段)
只管延长一些不须要的初始化工作,不要在启动时立即初始化全部对象。可以使用懒加载将一些初始化放到用户须要时再举行,以减轻启动阶段的负担。
4. 克制 +load 方法的使用(Initializers阶段)
+load 方法会在 dyld 加载阶段实行,发起用 +initialize 大概在符合的地方延长实行初始化逻辑,克制壅闭启动流程。
5.优化 AppDelegate(main()阶段)
application:didFinishLaunchingWithOptions: 方法应保持精简,克制在这里举行耗时的利用。将一些耗时任务放到背景队列中异步实行。
6.镌汰主线程壅闭
启动阶段只管克制主线程的耗时利用,如文件 I/O、网络哀求等。将这些利用放到子线程处置处罚,以免壅闭界面渲染。
7.预编译和瘦身
移除未使用的代码、图片等资源,精简应用的体积,从而镌汰加载时间。
只管镌汰 storyboard 的使用,尤其是大而复杂的 storyboard,可以分解成多个小的 storyboard 大概使用纯代码实现界面。
8.启动时的网络哀求
只管克制在启动时举行同步的网络哀求,如果必须哀求,可以在启动完成后或在背景举行异步哀求,以镌汰对启动时间的影响。
参考:
iOS--App启动过程及优化_ios启动优化-CSDN博客
https://juejin.cn/post/6951591401528229895?searchId=202502182003101C89E818EB9B45117D0A
JHBlog/iOS知识点/iOS大杂烩/APP启动优化/App启动时间优化.md at master · SunshineBrother/JHBlog · GitHub
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
页:
[1]