启动优化

image.png
  • main函数之前都干了什么
    dyld: 动态链接器, 把所有可执行文件以及动态库递归的加载到内存中
    rebase/bindging: rebase是指调整镜像内部的指针, bindging是指绑定外部函数的指针
    objc setup Runtime初始化, 加载类和分类的信息,
    load & initialize & constructor: 调用所有类和分类的load方法, 初始化C和C++的静态常量,调用attribute((constructor))修饰的函数
    image.png
按照不同阶段的优化
  • dyld
    减少动态库, 合并一些动态库(定期清理不必要的动态库)
    减少Objc类, 分类的数量, 减少Selector数量(定期清理不必要的类和分类)
    减少c++虚函数数量
    Swift推荐使用struct

  • runtime
    使用+initialize方法和disphtch_once来代替_attribute(constructor), c++静态构造器, 类的+load方法, 因为这些方法启动的时候就会调用[';;;;;;;, 如果我们在里面做了一些额外的操作, 就会增加启动耗时,我们其实可以根据一些实际情况放到其他地方去

  • main
    在不影响用户体验的前提下, 尽可能的将一些操作延迟, 不要全部都放在didFinishLaunchingWithOption

rebase

每次应用启动时,我们获取到的地址都是变化的, 虚拟内存技术出现后, 就出现了ASLR(地址空间布局随机) 如下图:


image.png

image.png

修正偏移(rebase)
那么问题来了: 既然我们每次启动应用地址都是随机的, 我们如何找到真正存储某个函数的地址呢
Link Map File : 链接映射文件, 里面记录了每个类所生成的可执行文件的路径,CPU架构,目标文件,符号等信息
在buildSettings- 设置 Write Link Map File为YES,将 Link Map File(链接映射文件)写入到本地

image.png

我们可以根据应用启动的ASLR随机地址, 和Link Map File里的方法偏移量和修复这函数的真是内存地址,这个过程就是rebase


image.png

比如我们的ASLR地址为0x0000000102c88000 viewDidLoad方法的偏移量为0x100001C04
那么我们可以得出viewDidLoad函数的真实地址
rebase的结果如下图

image.png

从上面的结果来看,rebase之后的地址就是 -[ViewController viewDidLoad]的真是地址

符号绑定bindging

主要是针对外部函数的绑定, 指的是在运行时通过外部符号去找到真正的存放这个外部函数的地址

3.1.3 无用类清理

从前面的分析章节我们知道,不管是 rebase&bind 还是 Objc Init 阶段,工程中类及分类的代码量都会影响这几个阶段的耗时,尤其是大型 App 中不断发展的业务导致代码量巨多,而很多业务和代码在上线后并没有用到,所以对于这些无用代码的清理也能减少启动耗时。另外,无用代码清理对于包大小的收益更大,云音乐在包大小优化中做了无用代码的清理6

那么,如何才能找出哪些代码没有被用到呢?一般可以分为静态代码扫描和线上大数据统计两种方式。静态代码扫描还是从 MachO 出发, MachO 中的_objc_selrefs_objc_classrefs两个 section 中存储了引用到的 sel 和 class,而在__objc_classlistsection 中存储了所有的 sel 和 class,通过比较两者数据的差集就可以获取没有被用到的类。而我们知道 OC 是一门动态语言,所以很多类都是运行时调用,在删除类之前需要确保没有被真正地调用。线上大数据统计则采用类元数据中相应的标记为是否被初始化来统计。我们知道,在 OC 中,每个类都有自己的元数据,在元数据中的一个标记位存储着自己是否被初始化,这个标记位不受任何因素影响,只要有被初始化就会打标记,在 OC 的源码中获取标记位的方式如下:

struct objc_class : objc_object {
    bool isInitialized() {
        return getMeta()->data()->flags & RW_INITIALIZED;
    }
}
 - (BOOL)isUsedClass:(NSString *)cls { 
     Class metaCls = objc_getMetaClass(cls.UTF8String); 
     if (metaCls) { 
         uint64_t *bits = (__bridge void *)metaCls + 32; 
         uint32_t *data = (uint32_t *)(*bits & FAST_DATA_MASK); 
         if ((*data & RW_INITIALIZED) > 0) { 
             return YES; 
         } 
     } 
     return NO; 
 }
image.png
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 217,734评论 6 505
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,931评论 3 394
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 164,133评论 0 354
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,532评论 1 293
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,585评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,462评论 1 302
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,262评论 3 418
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,153评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,587评论 1 314
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,792评论 3 336
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,919评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,635评论 5 345
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,237评论 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,855评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,983评论 1 269
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,048评论 3 370
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,864评论 2 354

推荐阅读更多精彩内容

  • 问题,APP启动慢,从启动到展示主页面视图需要5秒以上。 首先,研究APP启动流程。 优化方向,main函数之前和...
    小暖风阅读 1,390评论 0 1
  • 背景 一个项目做的时间长了,启动流程往往容易杂乱,库也用的越来越多,APP的启动时间也会慢慢变长。本次将针对iOS...
    lp_lp阅读 1,565评论 0 12
  • iOS之武功秘籍 文章汇总[https://www.jianshu.com/p/07991e5b1c30] 写在前...
    長茳阅读 1,126评论 0 16
  • App启动分成两部分 pre-main 阶段的定义为 APP 开始启动到系统调用 main 函数这一段时间 mai...
    川少叶阅读 572评论 0 0
  • App启动过程 app启动分为冷启动和热启动,热启动是App刚结束后再启动,有部分在内存但没有进程存在。我们所做的...
    coding_Liu阅读 909评论 0 1