美文网首页
App启动优化

App启动优化

作者: Fight_ing | 来源:发表于2020-12-16 14:25 被阅读0次
    一、冷启动和热启动
    • 定义:
      • 1.关于冷启动:业界对冷启动的定义没有问题,普遍认为是手机开机后第一次启动某个APP。
      • 2.关于热启动:
        对热启动有两种不同的看法:
        • 1.有些人认为是按下home键把APP挂到后台,之后点击APP的icon再拉回来到前台算是热启动;
        • 2.也有些人认为是手机开机后在短时间内第二次启动APP(杀掉进程重启)算是热启动(此时dyld会对部分APP的数据和库进行缓存,所以比第一次启动要快)。

    (一般认为APP从后台拉起到前台的时间没啥研究的意义,所以在统计启动时间时,会倾向于后一种说法,不过具体怎么定义看个人,知道其中的区别就好)

    如果启动过,内存页就已经加载进内存了,内存页如果要销毁只能是被覆盖,所以这时候的加载进物理内存的时候,实际内存中已经存在值,所以启动就会变快。

    二、优化的方向

    1.减少流程的数量。
    2.减少每个流程的消耗。

    三、APP的启动过程
    四、启动时间分布

    在Xcode中,可以通过设置环境变量来查看App的启动时间,DYLD_PRINT_STATISTICSDYLD_PRINT_STATISTICS_DETAILS


    根据xcode打印可以看到:
    动态库的加载
    • rebase/binding

      • 方法、类、Category这些需要rebase和 binding
      • binding
        Mach-O _DATA建立指针,指向外部函数,我们编译的时候,共享缓存库里边的代码指向的就是这里,链接的时候,通过dyld指向外部具体真实的地址。PIC技术
        fishook就是利用这个中转,hook的系统c函数。
    • Objc setup

      • 类的初始化过程在这里边
        ①读取二进制文件的 DATA 段内容,找到与 objc 相关的信息
        ②注册 Objc 类,ObjC Runtime 需要维护一张映射类名与类的全局表。当加载一个 dylib 时,其定义的所有的类都需要被注册到这个全局表中;
        ③读取 protocol 以及 category 的信息,把category的定义插入方法列表 (category registration),
        ④确保 selector 的唯一性
    • initializer
      load等函数,C++的构造函数

    耗时比较多的
    加载自己的库可能比较耗时

    两个阶段分别是 pre- main 和 main启动到viewDidAppear:



    pre-main过程:



    什么是dyld?
    dyld是一个专门用来加载动态链接库的库。

    执行从dyld开始,dyld从可执行文件的依赖开始, 递归加载所有的依赖动态链接库。

    五、 Dyld加载过程

    加载Mach-O文件,加载一块比较大的内存空间,地址重定向
    启动dyld的main函数

    • 配置xcode的环境变量 (arguments)
    • 加载共享缓存库,UIKit 和 Foundation这些

    加载LoadCommons段一系列加载
    加载动态库,包括自己的和系统的,实例化主程序的imageLoader,添加进imageList
    链接主程序

    开始初始化主程序
    *runtime配合加载,runtime加载loadImages方法,这个方法就是prepare_load_methods(mh)
    *加载load和C++构造函数
    找main函数

    配置(环境变量) — 加载(共享动态库,主程序,动态库) — 链接(链接主程序,动态库) — 初始化(程序)

    • 加载动态库过程,动态链接器dyld需要做如下操作
      1.分析依赖的动态库
      2.找到动态库的Mach-O文件
      3.打开文件
      4.验证文件
      5.在系统的内核注册文件签名
      6.对动态库的每个segment调用mmap()

    针对这一步优化

    1.减少非系统的动态库
    2.使用静态库而不是动态库
    3.合并非系统的动态库为一个

    1.动态库尽可能少,不要多与6个,如果多了,尽可能合并
    2.20000个类 800毫秒
    3.swift静态语言,性能更高

    六、ObjC SetUp

    由于之前2步骤的优化,这一步实际上没有什么可做的。几乎都靠 Rebasing 和 Binding 步骤中减少所需 fix-up 内容。因为前面的工作也会使得这步耗时减少。

    七、Initializers
    • 以上三步属于静态调整,都是在修改__DATA segment中的内容
      现在开始动态调整,在堆和栈中写入内容。 工作主要有:
      1、Objc+load()函数
      2、C++的构造函数属性函数 形如attribute((constructor)) void DoSomeInitializationWork()
      3、非基本类型的C++静态全局变量的创建(通常是类或结构体)(non-trivial initializer) 比如一个全局静态结构体的构建,如果在构造函数中有繁重的工作,那么会拖慢启动速度
      可以做的优化有:
      ①使用 +initialize 来替代 +load
      ②不要使用 atribute((constructor)) 将方法显式标记为初始化器,而是让初始化方法调用时才执行。 比如使用 dispatch_once(),pthread_once() 或 std::once()。也就是在第一次使用时才初始化,推迟了一部分工作耗时。 也尽量不要用到C++的静态对象。

    从效率上来说,在+load+initialize里执行同样的代码,效率是一样的,即使有差距,也不会差距太大。 但所有的+load方法都在启动的时候调用,方法多了就会严重影响启动速度了。 就说我们项目中,有200个左右+load方法,一共耗时大概1s 左右,这块就会严重影响到用户感知了。 而+initialize方法是在对应 Class 第一次使用的时候调用,这是一个懒加载的方法,理想情况下,这200个+load方法都使用+initialize来代替,将耗时分摊到用户使用过程中,每个方法平均耗时只有5ms,用户完全可以无感知。

    八、二进制重排

    iOS的虚拟内存和物理内存:



    之前所有应用都加载进内存条中,会有安全问题,会访问到其他人的软件中去

    iOS虚拟内存有4G的

    CPU通过 操作系统映射表 映射虚拟内存和物理真实内存
    也就是我们访问虚拟内存,都会走到映射表,然后映射到真实的物理内存。(每个映虚拟内存对应一个映射表)

    (mmp)分页加载,提高内存的利用率
    内存是以字节为单位,内存以页管理 PAGE,Linux每1页4KB,iOS每一页16KB

    用这种分页加载,用到哪块内存就加载到真实内存
    上述P2加载的时候,发现真实内存没有,缺页,CPU会临时加载

    如果启动的时候缺页比较多(缺页异常),就会不断去映射到物理内存,就会卡顿
    iOS的内存地址,与编译顺序有关,所以如果方法在不同的类,类的加载差距比较大,那么就会加载比较多的页,就会浪费时间。
    iOS系统还会对加载的每一页做签名认证,所以更加消耗时间。

    system trace
    Main Thread
    Virtual Memory File Backard Page In

    ldyd
    order_file 自己写一个文件,里边指定方法的顺序,可以将启动要调用的方法,都放到里边。
    libc-order在objc源码里边,这就是二进制重排

    所有OC方法获取
    用fishhook 去 HOOK objc_msgSend()方法,可以拿到所有的函数
    可以用Clang插庒的方式AOP

    八、main过程:
    • Main函数之后

    1.懒加载
    2.发挥CPU的价值,用多线程的方式。
    3.框架的搭建尽量避免stroyboard 和 xib

    • 分阶段加载:

    • 在didFinishLunch中启动的:

      • 埋点功能、
      • Crash 采集
      • 网络配置等
    • 在首页viewDidappear

      • 初始化SDK,友盟SDK、人脸识别SDK后移
      • 开始定位(显示定位中),定位可以缓存,先加载,定位同步进行,如果缓存的地理位置不一样,然后才更新
      • 配置下发等
    • 多线程启动

    尝试使用多线程启动
    将数据库的配置、SDwebimage UA的配置放到子线程中初始化,引入状态管理,需要监控子线程任务状态,判断是否取消假的开屏页面。

    广告同步加载,2秒回来了就展示,不回来就过
    Timer Profile的使用

    相关文章

      网友评论

          本文标题:App启动优化

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