美文网首页
iOS 启动过程分析及优化

iOS 启动过程分析及优化

作者: love_night | 来源:发表于2020-12-29 02:44 被阅读0次

    APP启动过程分析

    本文主要通过我们对于APP启动过程的分析,然后去剖析如何去进行启动时间的优化,以达到APP性能的提升。

    一:启动方式

    1.1 冷启动

    App 启动时,应用进程不在系统中(初次打开或程序被杀死),需要系统分配新的进程来启动应用。

    1.2热启动

    App 退回后台后,对应的进程还在系统中,启动则将应用返回前台展示。

    本次我们只针对于冷自动做主要分析。

    二:启动流程

    Apple 官方的《WWDC Optimizing App Startup Time》 将 iOS 应用的启动可分为 pre-main 阶段和 main 两个阶段,最佳的启动速度是400ms以内,最慢不得大于20s,否则会被系统进程杀死(最低配置设备)。

    因此:

    启动流程 = pre-main + main函数代理(didFinishLaunchingWithOptions)+ 首屏渲染(viewDidAppear)

    2.1 pre-main过程

    1.首先启动会加载解析APP的info.plist文件,因为该文件包含了APP加载所需要的众多配置项,例如APP启动图,是否全屏等等。
    2.创建沙盒(iOS8之后,每次启动都会生成一个新的沙盒路径).
    3.根据info.plist配置项检查APP所申请的权限状态。
    4.加载Mach-O文件,读取dyld路径并运行动态连接器。
    <1>首先dyld会寻找合适的cup运行环境。
    <2>加载程序所依赖的库以及.h/.m文件编译成的.o可执行文件,并对这些库进行连接。
    <3>加载所有方法,runtime就是在这个时候被初始化并完成OC的内存布局。
    <4>加载C函数。
    <5>加载类扩展,category,此时runtime会对所有类结构进行初始化。
    <6>加载C++静态函数,加载+load方法。
    <7>最后main函数被调用。

    Mach-O文件是 OS X 与 iOS 系统上的可执行文件格式,类似于windows的 PE 文件。像我们编译产生的.o文件、程序可执行文件和各种库等都是Mach-O文件。

    2.2main函数代理

    代理函数中didFinishLaunchingWithOptions执行

    - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions {
        self.window = [[UIWindow alloc] initWithFrame:[UIScreen mainScreen].bounds];
        [[UIApplication sharedApplication] setStatusBarStyle:UIStatusBarStyleLightContent animated:YES] ;
        [self setupSDKConfig];
        
        [RTPermissionManager registerRemoteNotification:self];
        [self switchRootViewController];
        self.window.backgroundColor = [UIColor whiteColor];
        [self.window makeKeyAndVisible];
        return YES;
    }
    

    2.3首页渲染
    home页面渲染。

    三:影响启动时间的因素

    对于APP的启动,可以说每一个时间段都有时间的性能问题,但是有些步骤损耗的时间非常短暂,如果我们花费大力气去处理,但是收益却很少,显然是不合适的,因此我们就从几个大的可以影响性能的方向入手。

    3.1 main 函数之前

    从上述的启动过程中可以看到,影响的因素很多,大体上可以分为:
    <1>动态库的数量。
    <2>OC类的数量,category的数量。
    <3>C的constructor函数越多,启动越慢。
    <4>C++静态对象越多,启动越慢。
    <5>OC类的+load方法。

    3.2 main 函数之后

    main函数之后,我们就是会执行Appdelegate中的代理以及首页页面的渲染,因此这一部分的影响因素,大体上可以分为:
    <1>执行main函数的耗时。
    <2>执行Appdelegate中的applicationWillFinishLaunching的耗时。
    <3>APP首页的渲染耗时。

    四:APP执行时间

    4.1 main函数之前

    我们可以通过xcode的方法,在Project→Scheme→Edit Scheme中通过设置参数,然后可以在控制台打印对应的时间日志。


    WX20201228-231524@2x.png

    xcode运行,我们可以得到准确的数据。

    iPhoneX
    Total pre-main time: 770.45 milliseconds (100.0%)
             dylib loading time: 150.62 milliseconds (19.5%)
            rebase/binding time:   6.02 milliseconds (0.7%)
                ObjC setup time:   9.22 milliseconds (1.1%)
               initializer time: 604.57 milliseconds (78.4%)
               slowest intializers :
        libMainThreadChecker.dylib :  45.22 milliseconds (5.8%)
              libglInterpose.dylib : 428.37 milliseconds (55.6%)
                       PuddingPlus : 189.86 milliseconds (24.6%)
    

    从上面可以看出,整个过程耗时770ms,其中我们分析,动态库的加载,initializer和libglInterpose比较耗时,好了,我们已经知道时间在哪里浪费了,那么接下来就可以具体去一一对应解决了。

    <1>加载动态库部分
    进行代码瘦身,code清理,同时清理无用的资源和代码,毕竟APP体积增大也会拖慢启动速度,排查项目中引用的动态库,及时删除无用的资源。
    <2>initializer 部分
    排查项目中+load方法的使用,规避一些在APP启动时的非必要操作,可以延迟到冷启动之后的某一个时间点来做。
    <3>libglInterpose
    据我查找,这个是Xcode在debug时会加载的一个动态库,本次不做深究。

    4.2 main函数之后

    时间我们可以通过main函数入口以及Appdelegate打印具体的时间。
    <1>main函数执行,如果里面没有主动加入任何耗时的任务,可以直接跳过。
    <2>Appdelegate中的didFinishLaunchingWithOptions方法的优化
    大部分APP在此方法中都会去实例化一些APP启动必须的类,或者注册一些监听,因此我们需要排查分析,是否每一个注册都是必须的,根绝我们的业务需要,适当的延后处理可不可以,比如APP的log日志部分,对于需要上传的日志部分,我们完全可以等到APP启动完成之后再做处理。
    <3>首页渲染
    *可以采取懒加载的方式,尽量延后执行我们所有类的实例化。
    *采用facebook的模式,预先加载无数据页面,等待网络请求返回数据在刷新页面。
    *采用缓存策略,预加载数据,减少用户等待的时间。

    五:结语

    对于快速迭代的App,随着业务复杂度的增加,冷启动时长会不可避免的增加。因此一次简单的优化是不行的,只能通过不断的努力,来不断的突破,同时还需要不要的监控日志平台分析数据,有效的业务管理,已经合理的设计,才能保证我们APP的良好体验。

    相关文章

      网友评论

          本文标题:iOS 启动过程分析及优化

          本文链接:https://www.haomeiwen.com/subject/rdwxoktx.html