基于公司项目的一次启动优化的尝试
一、启动时间统计
在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
网友评论