iOS启动优化:App 启动耗时 在线监控

数据存储在本地端硬盘区域里面以文件(夹)格式存在(普通文件、可执行文件、压缩文件等等各种文件)。应用APP程序正式启动之前需要消耗时间进行相关的数据文件文件数据的载入(过程:将相关的数据文件由本地端硬盘区域加载写入到内存里面)。
超大型项目中,往往不经意改动,可能会直接或累加式拖慢App启动速度,测试人员通过本地录屏或开发工具测量启动耗时由于受测试机状态、样本数量、个人状态等原因,结果数据往往有波动不能真正反馈App启动耗时的真实变化。所以加入 在线数据监控 变得非常重要。
一、App 启动耗时 在线监控
App应用启动过程:
iOS启动优化:App 启动耗时 在线监控_第1张图片
main()主函数前预准备阶段称为pre-main()阶段(红分割线左)。

pre-main()阶段开始时间:__t1
苹果公司并没有直接向开发者提供内部统计时间字段以供开发者直接获取App的启动开始时刻点,目前行业内主要有两种标准作为App的启动时间点:

第一种标准:以名称+(void)load方法被调用时的时间点
由于+(void)load 方法被调用的时间点发生Initializer初始化配置阶段, 根据(CompileSources)编译资源规则下动态库的加载顺序顺序的调用相应类下的+(void)load方法,因为动态库的加载顺序是递归加载的,所以我们只要找到最内部的叶子节点的动态库,然后在这个最内部叶子结点动态库中+(void)load方法重构以记录启动时间作为开始时间点。这种方式没有统计到Initializer初始化配置阶段前面部分所消耗的那些时间,比如在Initializer初始化配置阶段前面增加动态库、Category等造成的耗时并不能被及时发现统计。

第二种标准:获取整个进程创建(从开始到结束)消耗时间
App从源头配置直至运行整个过程实际上是一个逻辑进程,如果能获取到逻辑进程的起步创建时间即exec()可执行函数触发阶段的触动时间点作为整个app逻辑进程的开始时间点,能够更提前记录到App的启动开始时间点。

#import 
#import 
+ (CFAbsoluteTime)processStartTime {
    if (__t1 == 0) {
        struct kinfo_proc procInfo;
        int pid = [[NSProcessInfo 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;
}

pre-main()阶段结束时间点:__t2

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

void static __attribute__((constructor)) before_main() {
    if (__t2 == 0) {
        __t2 = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
    }
} 

为什么不用最后一个load方法执行时间作为pre-main()阶段的结束时间点?因为在超大型工程中我们没办法确定哪个名称load方法是最后一个被执行load方法。。。

启动动作正式完成对应的时间点:__t3
启动动作正式完成对应的时间点一般以didFinishLaunchingWithOptions:已完成启动对应的代理协议函数的结束时间点,但didFinishLaunchingWithOptions:已完成启动对应的代理协议函数的结束时间点(仅仅对应着光点初步渲染出现)其实不包括光点出现之后启动图动画渲染的时间消耗,而启动图动画执行完成后的时间点更加接近于用户的感官。可以在执行didFinishLaunchingWithOptions: 的runloop循环的后面的循环来获取时间:


- (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
{
    //do somethings
    dispatch_async(dispatch_get_main_queue(), ^{
        if (__t3 == 0) {
            __t3 = CFAbsoluteTimeGetCurrent() + kCFAbsoluteTimeIntervalSince1970;
        }
    });
    return YES;
}

你可能感兴趣的:(笔记,启动耗时,pre_main(),启动优化,App启动耗时,在线监控)