iOS启动时间,页面的加载时间优化

服务器断电了,所以得空来写点东西,之所以写这个问题是因为一次乌龙事件;我们项目上线引发了看门狗超时问题,就是那个eatBadfood,然后导致启动时间超时,高达27s,呵呵,啥玩意27s起不来啊,出问题设备是iPad但是我们测试时候没有遇到。

OK,那就是我的问题了吧,不多说启动超时我们就来处理启动超时的问题。

首先就是需要了解关于app启动的时候都干了什么事情,包括我们点击build按钮都干了什么:

当我们点击了 build 之后,做了什么事情呢?

预处理(Pre-process):把宏替换,删除注释,展开头文件,产生 .i 文件。

编译(Compliling):把之前的 .i 文件转换成汇编语言,产生 .s文件。

汇编(Asembly):把汇编语言文件转换为机器码文件,产生 .o 文件。

链接(Link):对.o文件中的对于其他的库的引用的地方进行引用,生成最后的可执行文件(同时也包括多个 .o 文件进行 link)。

其实通常对我们来说的话就是分为编译阶段和执行阶段;在我们app代码里面进行区分就是以main()函数为间隔区分这两个阶段,main()函数执行之前做的事情就是我们所要进行优化的地方了,即pre-main:在这段时间里系统会进行加载动态库、注册 Objc 类等系统操作。

在我们要优化之前首先我们要看一下,我们具体看一下启动时间到底是多少(系统方法):Edit scheme -> Run -> Auguments 将环境变量 DYLD_PRINT_STATISTICS 设为 1)然后运行,控制台就会打印我们的premain所用的时间。

Total pre-main time: 915.59 milliseconds (100.0%)

         dylib loading time: 499.70 milliseconds (54.5%)

        rebase/binding time:  48.53 milliseconds (5.3%)

            ObjC setup time:  24.47 milliseconds (2.6%)

           initializer time: 342.87 milliseconds (37.4%)

           slowest intializers :

             libSystem.B.dylib :  4.06 milliseconds (0.4%)

    libMainThreadChecker.dylib :  34.28 milliseconds (3.7%)

          libglInterpose.dylib : 124.91 milliseconds (13.6%)

                        Pretty : 263.99 milliseconds (28.8%)

  total time: 1.8 seconds (100.0%)

  total images loaded:  573 (523 from dyld shared cache)

  total segments mapped: 195, into 13129 pages

  total images loading time: 1.2 seconds (66.3%)

  total load time in ObjC:  24.47 milliseconds (1.2%)

  total debugger pause time: 759.18 milliseconds (40.0%)

  total dtrace DOF registration time:  0.00 milliseconds (0.0%)

  total rebase fixups:  279,519

  total rebase fixups time:  40.52 milliseconds (2.1%)

  total binding fixups: 720,435

  total binding fixups time: 222.74 milliseconds (11.7%)

  total weak binding fixups time:  8.30 milliseconds (0.4%)

  total redo shared cached bindings time: 223.03 milliseconds (11.7%)

  total bindings lazily fixed up: 0 of 0

  total time in initializers and ObjC +load: 342.87 milliseconds (18.0%)

                         libSystem.B.dylib :  4.06 milliseconds (0.2%)

               libBacktraceRecording.dylib :  5.84 milliseconds (0.3%)

                libMainThreadChecker.dylib :  34.28 milliseconds (1.8%)

                      libglInterpose.dylib : 124.91 milliseconds (6.5%)

                                  CoreDuet :  2.50 milliseconds (0.1%)

                       libMTLCapture.dylib :  2.71 milliseconds (0.1%)

              libViewDebuggerSupport.dylib :  8.01 milliseconds (0.4%)

                              FBSDKCoreKit :  4.42 milliseconds (0.2%)

                                    Pretty : 263.99 milliseconds (13.9%)

total symbol trie searches:    1703506

total symbol table binary searches:    0

total images defining weak symbols:  59

total images using weak symbols:  136

其实看起来还是很乱七八糟的,因为我在environment里添加了另外一行:DYLD_PRINT_STATISTICS_DETAILS为YES,然后打印的就如上这么详细了。

反正我当时看的时候是一脸懵逼,这都是啥,多亏了有大神指点,我们可以来详细的分析:

pre-main时间主要由 4 部分组成(原文搬运):

1.dylib loading:

这一阶段 dyld 会分析应用依赖的 dylib ,所以,依赖的 dylib 越少越好。在这一步,我们能做的优化就是检查是否存在不需要的 dylib ,移除不必要的 dylib 。

在项目优化实践中,我们移除了一个没有必要的动态库,并将几个动态库合成为一个动态库,减少动态库数量。

2.rebase/binding:

这一阶段系统主要注册 Objc 类。所以,指针数量越少越好。这一步能做的优化有:

清理项目中无用的类

删减没有被调用到或者已经废弃的方法

删减一些无用的静态变量

可通过 AppCode 等工具扫描项目中未使用的代码。

3.Objc srtup:

这一阶段没有什么特别能优化的地方,如果 rebase/binding 阶段优化的好这步耗时也会很少。

4.initializer:

这一阶段,dyld 开始运行程序的初始化函数,调用每个 Objc 类和分类的 +load 方法,调用 C/C++ 中的构造器函数。initializer阶段执行完后,dyld 开始调用 main() 函数。在这一步,检查 +load 方法,尽量把事情推迟到 +initiailize 方法里执行。

在这里我们修改了部分原本代码中直接在 +load 函数初始化逻辑改为在 +initialize 中加载,也就是到使用时才加载。

参考以上的教程,我寻找了我们app的需要优化的地方,拼命减少了一个动态库,还有几个三方库,把一些用来测试的指针都给干掉了,当然因为是新的app,所以没有用app code检测,以后可以使用试试。

虽然我没看出来启动时间有啥进步,但是改了就是进步了啊;美滋滋提交,求神拜佛,结果同样问题,同样结果。

我就开始总结,这个问题一开始就和启动时间没有关系啊,再超时也不可能27s嘛,第二次打回来告诉我32s,这就更离谱了,所以我进行了错误日志解析,呵呵,原来是三方库的问题(百度地图sdk导致);所以建议在finishLaunch的时候部分三方注册,代理的内容可以放到子线程做。

我们回过头来看启动时间的问题,我们通过上面对照能够看懂我们程序所打印的内容,如果能够获取程序在各个页面显示出来所占用的时间,然后我们才能进行具体优化,判断是否有我们肉眼所看不到的卡顿问题。

下面是正文:

1.premain()以后的显示的页面时间优化

    (1).在我们首页显示之前,尽量减少操作。

    例如:各种网络请求,能省就省了吧;能用代码构建UI,尽量少用xib;手势等添加可以在页面显示之后;减少加载的view controller的加载数量;部分可以延时处理的操作可以放到子线程。

    至于使用动画,个人觉得就算了吧,如果不是特别熟练清楚底层原理,建议不要使用(动画不会被主线程阻塞)

    (2).页面卡顿的优化

    这里感觉能优化的就有很多了,可以通过bugly来监测一些卡顿问题,通过具体代码去解决问题。

    还有关于CPU和GPU,页面渲染相关的问题我也正在学习阶段,建议大家多读大神文章,一起学习吧。毕竟我也是菜的不行。

2.页面加载耗时打印

    打印各个页面加载时间,有助于我们发现很多平时看不到的问题,对比得到哪些页面需要去优化。

    下面我来介绍一下具体方法:

    我们想要了解加载页面的view消耗的时间需要知道VC的生命周期:

    1.initWithCoder: 通过 nib 文件初始化时触发。

    2.awakeFromNib: nib 文件被加载的时候,会发生一个 awakeFromNib 的消息到 nib 文件中的每个对象。

    3.loadView: 开始加载视图控制器自带的 view。

    4.viewDidLoad: 视图控制器的 view 被加载完成。

    5.viewWillAppear: 视图控制器的 view 将要显示在 window 上。

    6.updateViewConstraints: 视图控制器的 view 开始更新 AutoLayout 约束。            

    7.viewWillLayoutSubviews:视图控制器的 view 将要更新内容视图的位置。

    8.viewDidLayoutSubviews: 视图控制器的 view 已经更新视图的位置。

    9.viewDidAppear: 视图控制器的 view 已经展示到 window 上。

    10.viewWillDisappear: 视图控制器的 view 将要从 window 上消失。

    11.viewDidDisappear: 视图控制器的 view 已经从 window 上消失。

    所以,我们只需要在loadview的时候打印一下当前时间[[NSDate date] timeIntervalSince1970],因为获取到的时间单位是秒,建议*1000换算成毫秒,看起来比较直观。在viewDidAppear里面再打印一次当前时间,两个时间的差值就是页面的加载时间啦,如果加载时间太久,那就需要进行优化了。(也得根据自己的代码具体细节进行调整,建议在loadview进行UI布局)

刚刚打印了一下时间:当前开始加载1577944446238

当前结束加载1577944446251

这不是扯么,速度这么快?我都不信,但是这是事实,这是没有进行网络加载的,单纯的加载UI的时间,不包括刷新方法;你需要在你需要的地方进行布局埋点,统计这个页面的加载时间。

有更好的方法的小伙伴,欢迎留言。

参考:https://www.jianshu.com/p/6387eba2ea16

https://www.cnblogs.com/junhuawang/p/7598236.html

https://www.jianshu.com/p/fe566ec32d28

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