app的启动时间是衡量一个app性能的重要指标,是用户对这个app的的第一映象,启动时间的快慢会直接影响用户对这个app的使用体验,那怎样能使程序更快的启动呢?
app的启动分为冷启动和热启动
热启动:App在冷启动后用户将App退回后台,此时App的进程还在系统里。用户重新返回App的过程。(热启动做的事较少)
冷启动:App点击图标启动前,此时App的进程还不在系统里。需要系统新创建一个进程分配给App。(这是一次完整的App启动过程)
主要优化是针对冷启动,最佳启动时间应小于400ms,并且程序被限制启动时间不能大于20s,否则会因为看门狗机制而被杀掉。对于恢复悬挂不能大于10s,APP在后台已经运行的 不能超过十分
冷启动流程:
预编译-> 编译->汇编->链接(静态链接和动态链接)
一.dyld阶段:动态链接器 .h .m .cpp .swift,在我们点击run的时候就会生成mach-o的可执行文件
lg:在我们run程序之后,可以从product-> Show Build Folder in Finder ->Products->Debug->xxxx->显示包内容->xxxx的可执行文件是mach-o()格式的
主要处理在源代码中以#号开头的预编译的命令lg:#include,#import,将包含的的文件插入到编译的指定位置,删除一些注释,替换宏之类的。
系统调用exec文件就会创建进程,接下来:
1把可执行文件加载到内存
2.dyld加载到内存
3.dyld进行动态链接 -> rebase bingding(虚拟内存概念)重定向修正指针
二.runtime阶段,ObjC的runtime初始化,包括:ObjC相关Class的注册、category注册、selector唯一性检查等。
以上是main函数指向之前,优化思路(减少类和方法的数量,合并动态库(自己写的不多于6个动态库),延时加载,二进制重排等),由于load方法会在main函数之前执行调用,load函数里面不要有耗时的操作,尽可能将里面的内容放到渲染完成后做。可以使用initialize代替load。优化类、方法、全局变量 减少加载启动后不会去使用的类或方法;少用C++全局变量;
三.main函数的初始化,main函数执行UIApplicationMain函数,就会进入应用的生命周期,调用didfinishlaunch这个方法(主要在这个方法里面做优化)我们一般会在这里面定位、统计、分享之类sdk的初始化,而这个过程是首屏渲染相关方法执行完成,从main函数执行到设置self.window.rootViewController执行完成的阶段。主要是首屏渲染相关的所有方法执行,见图
针对此过程的优化:不是一启动就必须要使用的东西不要启动项目时初始化善用异步,优化主线程,先处理会卡住主线程的方法,不能影响到用户的后续操作。
检测启动速度:edit scheme 设置key为:DYLD_PRINT_STATISTICS ,value为:1 就可以在控制台打印出启动app所花费的时间
补充:
一.
load:在main函数之前调用(exchange_method),系统直接寻址调用,一般不会自己调用,由系统调用,调用子类的load之前会先检查是否调用过父类,没有调用过父类会先调用父类再调用子类
initialize:在第一次向类发送消息时调用(初始化),msgSend调用,调用子类之前会先调用父类,子类没有实现该方法会调用父类,所以父类的该方法可能会被调用多次,调用子类的initialize之前会先检查是否调用过父类,没有调用过父类会先调用父类再调用子类
二.
静态库:一堆的.o文件的集合 ,编译打包之后不复存在
优:静态库访问速度快,被链接到app之后的体积比较小
缺:产物的体积比较大
动态库:一个已经链接完全的镜像,动态库影响启动速度
优:动态库能共享,节省空间,产物体积比较小
缺:链接到app之后体积比较大
自己做的动态库,能共享吗?
不能,只能跟扩展共享,扩展与app共用一个进程,公司内部组件,一般都是静态库,接入的第三方一般是动态库,因为保密性比较好。