iOS App启动优化

iOS的App启动一般有两个过程,发生在main函数前的过程和main函数之后的过程。

main函数前

App开始启动后,系统首先加载可执行文件(即App所有.o文件),然后加载动态链接库dyld,dyld是一个专门负责加载动态链接库的库(the dynamic link editor工具),dyld会加载所有可执行文件(.o文件)的依赖动态库,包括App使用到的所有系统 framework,还有一些runtime和系统级别的lib,如libobjc、libSystem等

简单来说,上述所说的可执行文件(.o文件)和动态库都可以称为image。

所有动态链接库、App集成的静态库、所有类文件编译后的.o文件最终都是由dyld这个工具加载到内存中。每个image都是由一个叫做ImageLoader的类来负责加载。

ImageLoader

这里的image并不是代表图片的意思,表示一个二进制文件(可执行文件或 so 文件),里面是被编译过的符号、代码等,所以 ImageLoader 作用是将这些文件加载进内存,且每一个文件对应一个ImageLoader实例来负责加载。

大概流程

1、dyld 开始将程序二进制文件初始化
2、交由 ImageLoader 读取 image,其中包含了我们的类、方法等各种符号
3、由于 runtime 向 dyld 绑定了回调,当 image 加载到内存后,dyld 会通知 runtime 进行处理
4、runtime 接手后调用 mapimages 做解析和处理,接下来 loadimages 中调用 callloadmethods 方法,遍历所有加载进来的 Class,按继承层级依次调用 Class 的 +load 方法和其 Category 的+load 方法。

至此,可执行文件中和动态库所有的符号(Class,Protocol,Selector,IMP,…)都已经按格式成功加载到内存中,被 runtime 所管理,再这之后,runtime 的那些方法(动态添加 Class、swizzle 等等才能生效)。

简单来说就是
dyld加载各种库---->ImageLoader读取 image ---- >runtime初始化环境

优化

对于main()调用之前的耗时我们可以优化的点有:
1、减少动态库,官方建议6个,不要链接那些用不到的库(包括系统)。
2、检查+load()方法是否合理
3、合并或者删减一些OC类,关于清理项目中没用到的类。
4、二进制重排,减少page fault的次数

启动时间计算

pre-main的大概过程可以简述为

加载可执行文件、加载动态链接器dyld、按照依赖加载动态库

为了获得启动时间,可以在第一个动态库开始记录启动时间,但是在加载动态库之前还有一段时间我们记录不到。
所以这时候可以换一个方法。
使用OC的NSProcessInfo类,获取App创建进程的时间戳。

#import <Foundation/NSProcessInfo.h>
#include <sys/types.h>
#include <sys/param.h>
#include <sys/sysctl.h>

//// 根据进程ID,获取进程信息!
+ (BOOL)processInfoForPID:(int)pid procInfo:(struct kinfo_proc*)procInfo
{
    int cmd[4] = {CTL_KERN, KERN_PROC, KERN_PROC_PID, pid};
    size_t size = sizeof(*procInfo);
    return sysctl(cmd, sizeof(cmd)/sizeof(*cmd), procInfo, &size, NULL, 0) == 0;
}
//  根据进程信息,获取具体的进程加载到内存中的时间戳
+ (NSTimeInterval)processStartTime {
    struct kinfo_proc kProcInfo;
    if ([[self class] processInfoForPID:[[NSProcessInfo processInfo] processIdentifier] procInfo:&kProcInfo]) {
        return (kProcInfo.kp_proc.p_un.__p_starttime.tv_sec * 1000.0 + kProcInfo.kp_proc.p_un.__p_starttime.tv_usec / 1000.0);
    } else {
        NSAssert(NO, @"无法取得进程的信息");
        return 0;
    }
}

启动之后,进入main函数之后到applicationDidBecomeActive,才算启动结束。
所以统计创建进程的时间戳到BecomeActive时间戳时间的时间差即可。

启动函数耗时

Instrument中的 Time Profiler工具,可以查看App在某一段时间的方法耗时,大概原理如下。

1ms 采样一次,只采集在运行线程的调用栈,最后以统计学的方式汇总。注意,每1ms采样,Profiler看堆栈的方法,如果有,那么这个方法就叠加 1ms,事实上并不是代码实际执行的时间,不是很准确的,有可能会遗漏,而是栈在采样统计中出现的时间

除了使用 Time Profiler工具,我们还可以使用fishhook工具,hook objc_msgSend方法,用来统计每个方法(包含第三方SDK静态库内部的方法)的启动耗时。本质上是在方法的开始和末尾打两个点,就知道这个方法的耗时,然后转换成 Chrome 的标准的火焰图 json 格式,将该json文件传入分析工具chrome://tracing/生成火焰图,通过以下火焰图,我们可以非常方便的看到启动时执行了哪些方法和耗时的多少。

软件的性能分析,往往需要查看 CPU 耗时,了解瓶颈在哪里。
火焰图(flame graph)是性能分析的利器。


image.png

main函数后

在main()被调用之后,
执行
- (BOOL)Application:(UIApplication *)Application didFinishLaunchingWithOptions:(NSDictionary *)launchOptions
然后在这个方法必要的服务,配置第三方库、显示首页内容等。
可以优化的点:
1、尽量使用代码布局UI,避免使用XIB、storyboard。
2、一些在didFinishLaunchingWithOptions的配置或者创建可以使用懒加载,或者延后创建。

参考文章

https://techblog.toutiao.com/2017/01/17/iosspeed/

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,684评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 87,143评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,214评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,788评论 1 277
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,796评论 5 368
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,665评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,027评论 3 399
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,679评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 41,346评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,664评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,766评论 1 331
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,412评论 4 321
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 39,015评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,974评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,203评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,073评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,501评论 2 343