启动速度优化背景:

我们的项目在项目为一个开发迭代多年的老项目,之前对项目的启动性能没有太多的关注,导致APP的启动速度比较慢,启动有时要耗时3、4s钟,整体启动性能堪忧。我们主管安排我负责优化,全力优化APP启动速度。

遇到挑战:

最大挑战有2个,一是代码历史代码性能消耗没有把控,很多地方存在不合理的代码;二是做为入职不久的新人需要在1个月完成左右优化,时间紧任务重;

优化步骤:

首先我们梳理好目标,iOS启动可以分为冷启动和热启动。冷启动是指APP本身不在后台系统,从用户点击应用icon到appDelegate didFinishLaunching方法执行完成用户看到APP首页为止;热启动是APP本身在系统后台运行,从后到点击到进入APP场景。我们重点是优化冷启动的速度,启动速度时间目标由3s降到1.2s;
有了明确目标后接下来是对目标进行拆解,要进行冷启动优化我们需要知道冷启动过程具体做了什么,具体哪部分执行节点耗时较多。APP冷启动可以大概分为三个阶段,第一阶段是main函数之前,系统执行一系列加载和链接工作;第二阶段是main函数之后,从main函数开始到AppDelegate的didFinishLaunchingWithOptions执行完毕;第三阶段是从didFinishLaunchingWithOptions执行到APP渲染出APP的首页;我们需要从这三个阶段来进行优化,首先我们需要分析这三个阶段的耗时情况。
测算main函数之前的耗时,我们可以通过配置xcode来进行,在xcode的editScheme中Run→ Environment Variables 添加name为DYLD_PRINT_STATISTICS为1,这样就可以在xcode控制台中一份输出报告示例如下:

从上图中我们可以清晰了解main函数前的耗时,以及过程中加载动态库耗时、oc类初始化耗时、指针重定义耗时。对于main函数后我们可以通过加入计时代码来统计,这块统计比较简单;

main函数前核心优化:主要包括优化动态加载库、Rebase/Binding优化和优化初始化阶段

动态库加载优化:
我们主要进行2方面的优化,
1.消灭内嵌的动态库,因为系统加载内嵌动态库会消耗比较大的性能;
2.减少动态库的数量,可以通过合并已有的动态库来达到目的,动态库越多性能开销越多;

Rebase/Binding优化:
主要进行了2类优化,
1.减少oc类、减少方法、减少分类数量;
2.使用Swift structs可以大幅减少符号数量;

Initializers阶段优化:最核心是减少load方法使用,load执行代码越多启动会越慢,我们可以把load的实现代码延迟放到initiailize方法中,在initiailize方法不会影响APP的启动速度;

main函数后阶段优化:这个阶段核心优化思路是减少主线程的性能消耗,对于基础组件的初始化做到能延后的延后,能放到子线程初始化的放到子线程初始化。
通过以上优化后我们APP的启动速度有了很大的提升,由原来的3s出头优化到了1.2s左右。

接入总结和建议:整体接入还是比较简单,官网在整体的说明文档方面比较清晰。整个apm在崩溃做的比较好,对比之前用的听云和bugly还是不错的,在信息收集的全面性方面特别好,另外对于崩溃日志解析和准确性方面比较好,崩溃的堆栈相对其他产品更易懂。

对产品的建议:在使用过程中发现以下问题建议参考优化
(1) 从u-apm注册后,在之后的主页就找不到关于u-apm的内容了,注册完后注册了一个APP发现是接入友盟基础SDK,不是我想要的,只能通过返回到活动也才找到u-apm。
(2) 想接入一个没有idfa的版本,没找到,看接入注意是强制收集了idfa,定位和idfa国家对我们这个行业有限制,特别是位置权限不允许用;
(3) 官网上播放视频和下面的介绍叠在一起,无法全屏看(Safari浏览器)
(4) 概览中,崩溃率、ANR描述使用专门名词,现在都使用“错误“统称,并不符合开发的认知,比如崩溃就是崩溃率,anr就说是anr,而不是统称为崩溃;
(5) 实时概览更希望看的是一些总的数据表,比如崩溃Android崩溃希望看java和原生底层加起来的总崩溃,另外建议实时概览增加卡顿率、网络错误率、启动速度等一些关键指标的总览图;二级页面再增加卡顿、崩溃等详情;

作者:盛夏
从事iOS开发5年,做过社交和教育APP研发

03-06 00:04