终于把影响App冷启动的元凶抓到了,OpenUDID。整理回顾下整个过程。
具体发现的过程见上一篇
现象1:问题已经锁定到【刚进入main】到【刚进入didFinishLaunchingWithOptions】之间,通过打点会发现这两处直接会消耗1.5s左右。这就限入了困境,这两点直接我们是做不了任何事,只有进didFinishLaunchingWithOptions后才有业务代码。
现象2:更蹊跷的是,我手里有两台手机iPhone6和iPhone5s,这个问题只在iPhone6上有发生。
尝试1:建了一个空工程,通过运行可见启动速度很快,没有上述问题;可以判断问题还是和我的工程有关。
尝试2:找了《美团外卖iOS App冷启动治理》作者求助。作者回信告知他没有遇到这样的情况,并建议我使用time profile找找,因为进入main函数后所有的调用过程都可以通过time profile看到。 在他建议下我分别在iPhone5s和iPhone6 上运行了下time profile,耗时分别在1s和1.5s,再看下具体耗时函数也就在100ms左右。我要找的时1.5s左右的耗时,就没有继续关注。实际证明,在这里我错过一个抓住问题的计划。
尝试3:巧办法没起作用,就用笨办法了。一点点从工程了删库、删第三方代码、删业务代码,最后就留下了一张空首页,还是没找到问题点。能看的见的UI都删完了,接着删看不见的服务。奇迹终于发生了,在我删除一个主题管理服务后(动态下载最新页面主题),这1.5s的延时没有了。于是赶紧恢复成完整工程,然后在完整工程里,只移除了这个主题管理服务。发现之前两点间的1.5s延时确实没有了。可是总觉得启动还是和之前一样慢,手动计时了下证实自己的想法。很困惑,也没有好办法,继续往后打点。首页内容由三个顺序的网络请求完成,在三个请求间隔都打上了点。运行后发现第一点耗时很长,注释掉第一个请求。奇怪的是再运行原本的第二个请求也耗时了。
我的推断,难道第一个网络请求一定会耗时?测试了确实如此,于是我开始怀疑底层第三方网络库的问题。这个是有灵光闪现了下,与其到处打点何不用time profile来试下:于是发现了用的第三方代码 OpenUDID有很大问题。
说明下为什么要用OpenUDID。我用OpenUDID来获取伪唯一机身号,并在每个网络请求里都带上这个值,用于后台统计和其他业务目的。既然锁定了问题根源,倒推回去看看能不能解释之前的现象。
现象1:为什么耗时问题只在iPhone 6上发生?通过测试发现,在生成OpenUDID的代码里有个内循环,在iPhone 5s上只会跑进去6次,而在iPhone 6上会跑上86次。(OpenUDID生成的原理我还没仔细看)
现象2:为什么在之前工程里,会【刚进入main】到【刚进入didFinishLaunchingWithOptions】的时候产生耗时。原因是,主题下载服务是用+(void)load里发起了网络请求,猜想这个请求只能缓存在那里,直到main函数获得控制才得以执行。当然这个写法是有问题的,只要注册对应的系统消息就可以。
那为什么会在第一次使用time profile时完美错过一次发现问题的机会?因为我把目标锁定在寻找1.5s的耗时,没去注意看100ms的耗时。当然time profile显示耗时和实际打点获得的耗时有很大差距。具体原因不详,至少可以借助time profile发现问题,再用打点方法精确确定时长。
这里还有个遗留问题:OpenUDID设计的目的是不依赖硬件号来生成一个唯一编号,其作用是什么好需要进一步了解。
看着唰一下就打开的App心里无比痛快。实际上早几个月产品经理就提出了启动慢的问题,一直没有重视。
上图留念
Time Profile
网友评论