启动优化尝试

基于公司项目的一次启动优化的尝试

一、启动时间统计
在Xcode13前,通过增加key能实现打印启动时间的功能,在Xcode13后,使用DYLD_PRINT_STATISTICS发现并不会打印启动时间。找了个替代方案

//
//  IMIAppLaunchTime.m
//  CMKit_Example
//
//  Created by Roffa Zhou on 2022/7/1.
//  Copyright © 2022 xxx. All rights reserved.
//

#import "IMIAppLaunchTime.h"

#import <sys/sysctl.h>

#import <mach/mach.h>


@implementation IMIAppLaunchTime


double __t1; // 创建进程时间 毫秒

double __t2; // before main

double __t3; // didfinsh

/// 获取进程创建时间
+ (CFAbsoluteTime)processStartTime {

    if (__t1 == 0) {

        struct kinfo_proc procInfo;

        NSProcessInfo *processInfo = [NSProcessInfo processInfo];
        int pid = [processInfo processIdentifier];

        int cmd[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};

        size_t size = sizeof(procInfo);

        if (sysctl(cmd, sizeof(cmd)/sizeof(*cmd), &procInfo, &size, NULL, 0) == 0) {

            __t1 = procInfo.kp_proc.p_un.__p_starttime.tv_sec * 1000.0 + procInfo.kp_proc.p_un.__p_starttime.tv_usec / 1000.0;

        }

    }

    return __t1;

}
/// 开始记录:在DidFinish中调用

+ (void)mark {

    double __t1 =  [IMIAppLaunchTime processStartTime];
    
    dispatch_async(dispatch_get_main_queue(), ^{ // 确保didFihish代码执行后调用

        if (__t3 == 0) {

            __t3 = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;

        }

        double pret = __t2 - __t1 / 1000;

        double didfinish = __t3 - __t2;

        double total = __t3 - __t1 / 1000;

        

        NSLog(@"----------App启动---------耗时:pre-main:%fs",pret);
        NSLog(@"----------App启动---------耗时:didfinish:%fs",didfinish);
        NSLog(@"----------App启动---------耗时:total:%fs",total);

    });
}

/// 构造方法在main调用前调用
/// 获取pre-main()阶段的结束时间点相对容易,可以直接取main()主函数的开始执行时间点.推荐使用__attribute__((constructor)) 构建器函数的被调用时间点作为pre-main()阶段结束时间点:__t2能最大程度实现解耦:

void static __attribute__((constructor)) before_main() {

    if (__t2 == 0) {

        __t2 = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;

    }

}

@end

计算load的时间是通过在Compile Sources中第一个文件增加load时间戳打印,再再main方法中增加时间戳打印,可能不准确,但是也能当一个load的运行时间作为判断了
NSLog(@"-------------App启动 main begin: %f", CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970);
经过统计得到各时间段如下,5次得到的结果(取5次中出现总耗时相对最稳定的一个值为参照基准,此次测试取总耗时1.8s为基准,与此值相差100ms以上的结果剔除)

描述 第一次 第二次 第三次 第四次 第五次 5次平均
load方法耗时 43ms 38ms 43ms 41ms 42ms 41ms
pre-main耗时 1.243s 1.213s 1.220s 1.238s 1.192s 1.295s
didfinish耗时 622ms 580ms 582ms 601ms 621ms 601ms
总耗时 1.865s 1.793s 1.802s 1.839s 1.813s 1.822s

综上,pre-main耗时较多,由于处理pre-main相对更为复杂,因此先从didfinish耗时开始进行优化


didFinish优化过程

  • 主线程异步执行可以暂缓执行的方法
//下面方法被移动到异步执行
dispatch_async(dispatch_get_main_queue(), ^{ // 确保didFihish代码执行后调用
        ILLogV(@"didFinishLaunching");

        //打印系统信息
        [self printSystemInfo];
        //设置显示样式
        [self initDisplayStyle];
        /// 设置APP更新本地存储
        [self setAppUpdateClickCancel];
        [self push_application:application didFinishLaunchingWithOptions:launchOptions];

    });

通过此次优化后,耗时结果如下

描述 第一次 第二次 第三次 第四次 第五次 5次平均
load方法耗时 43ms 38ms 43ms 41ms 42ms 41ms
pre-main耗时 1.275s 1.204s 1.199s 1.192s 1.205s 1.215s
didfinish耗时 588ms 604ms 596ms 594ms 585ms 593ms
总耗时 1.863s 1.809s 1.794s 1.786s 1.790s 1.808s

此次耗时统计对启动时间的优化不是特别明显,总耗时优化了1帧左右

  • 主线程异步创建首页相关视图、第三方sdk
    改造前
 [self initThirdSDKConfigWithApplication:application options:launchOptions];
 [self initManagerConfig];
 [self initWindows];          
 [self.window makeKeyAndVisible];
 [self initViews];

改造后

dispatch_async(dispatch_get_main_queue(), ^{ // 确保didFihish代码执行后调用
     //开始初始化
     [self initThirdSDKConfigWithApplication:application options:launchOptions];
     [self initManagerConfig];
     [self initViews];
 });
 [self initWindows];
UIViewController *launchVC = [[UIStoryboard storyboardWithName:@"LaunchScreen" bundle:nil] instantiateViewControllerWithIdentifier:@"launchScreen"];
self.window.rootViewController = launchVC;
[self.window makeKeyAndVisible];

由于视图采用异步绘制,会有瞬时的闪动,为了处理此问题,增加了读取启动图vc,默认先把启动图作为rootview

描述 第一次 第二次 第三次 第四次 第五次 5次平均
load方法耗时 43ms 38ms 43ms 41ms 42ms 41ms
pre-main耗时 1.312s 1.411s 1.258s 1.249s 1.368s 1.319s
didfinish耗时 259ms 271ms 286ms 258ms 285ms 272ms
总耗时 1.571s 1.682s 1.544s 1.507s 1.653s 1.591s

didfinish耗时从最初的601ms下降到272ms,优化了大概339ms,总耗时从1.822s下降到1.591s, 优化了大概231ms

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

推荐阅读更多精彩内容