美文网首页
App 启动速度怎么做优化与监控?

App 启动速度怎么做优化与监控?

作者: zhouluyao | 来源:发表于2020-04-30 15:13 被阅读0次

    main() 函数执行前

    1、加载可执行文件(App 的.o 文件的集合);

    2、加载动态链接库,进行 rebase 指针调整和 bind 符号绑定;提高启动速度减少动态库加载非常关键

    3、Objc 运行时的初始处理,包括 Objc 相关类的注册、category 注册、selector 唯一性检查等;

    4、初始化,包括了执行 +load() 方法、attribute((constructor)) 修饰的函数的调用、创建 C++ 静态全局变量。+load() 方法里的内容可以放到首屏渲染完成后再执行,或使用 +initialize() 方法替换掉。因为,在一个 +load() 方法里,进行运行时方法替换操作会带来 4 毫秒的消耗。不要小看这 4 毫秒,积少成多,执行 +load() 方法对启动速度的影响会越来越大。

    main() 函数执行后

    从功能上梳理出哪些是首屏渲染必要的初始化功能

    哪些是 App 启动必要的初始化功能

    哪些是只需要在对应功能开始使用时才需要初始化的

    梳理完之后,将这些初始化功能分别放到合适的阶段进行。

    优化的思路是:

    1、main() 函数开始执行后到首屏渲染完成前只处理首屏相关的业务,其他非首屏业务的初始化、监听注册、配置文件读取等都放到首屏渲染完成后去做。

    2、进一步要做的是检查首屏渲染完成前主线程上有哪些耗时方法,将没必要的耗时方法滞后或者异步执行。

    可以注意的点有:

    1、除了用户看到的第一屏内容所依赖的初始化方法(UI和基础服务),尽量以异步,甚至是后台线程的方式来做初始化。

    2、其他服务的初始化通常都会等到真正需要调用的时候才被执行。

    3、对于第三方库,都是在AppDelegate.didFinishLaunchWithOptions方法中执行的,而这个方法是在主线程上,会阻塞用户操作,虽然每个sdk都建议在didFinishLaunchWithOptions中做初始化,但其实大多都没有这么紧急,稍微延后一些也是完全可以接受的,这样就大大减轻了启动代码的工作量。

    有哪些手段能够对启动方法耗时进行全面监控呢?

    第一种方法是,定时抓取主线程上的方法调用堆栈,计算一段时间里各个方法的耗时。

    第二种方法是,对 objc_msgSend 方法进行 hook 来掌握所有方法的执行耗时。objc_msgSend 方法干的活儿,就是在运行时根据对象和方法的 selector 去找到对应的函数指针,然后执行。

    打印方法调用栈

    第一步,设计两个结构体:CallRecord 记录调用方法详细信息,包括 obj 和 SEL 等;ThreadCallStack 里面,需要用 index 记录当前调用方法树的深度。有了 SEL 再通过 NSStringFromSelector 就能够取得方法名,有了 obj 通过 object_getClass 能够得到 Class ,再用 NSStringFromClass 就能够获得类名。

    第二步,pthread_setspecific() 可以将私有数据设置在指定线程上,pthread_getspecific() 用来读取这个私有数据。利用这个特性,我们就可以将 ThreadCallStack 的数据和该线程绑定在一起,随时进行数据存取。

    第三步,因为要记录深度,而一个方法的调用里会有更多的方法调用,所以我们可以在方法的调用里增加两个方法 pushCallRecord 和 popCallRecord,分别记录方法调用的开始时间和结束时间,这样才能够在开始时对深度加一、在结束时减一。

    相关文章

      网友评论

          本文标题:App 启动速度怎么做优化与监控?

          本文链接:https://www.haomeiwen.com/subject/omrzwhtx.html