• APP项目优化--启动速度优化篇


      我们所开发的项目,随着线上功能逐渐稳定,导致项目启动速度越来越慢,而这又是用户对我们的项目给第一印象,所以启动速度变得尤为重要,如果启动速度缓慢,会造成比较严重的用户流失,所以,对启动速度的优化,将会成为我们后期开发工作中不可或缺的一部分。

     基础概念

      冷启动:是指启动并没有进程在系统里,需要系统新创建一个进程供APP使用的启动情况

      热启动:和冷启动对应,是APP的进程在系统里,用户重新启动进入APP的过程,如果把APP进程杀掉,然后立即重启,也属于热启动因为进程的缓存依然存在

      其实,从用户可感知的维度去看呢,就是用户在手机桌面,点击APP图标,到APP启动图完全消失,首页第一帧渲染完成的过程。所以,本文我们就只展开说APP冷启动的流程和优化。

      启动流程

      总得来说APP启动主要包括三个阶段:

      1、main()函数执行之前

      2、main()函数执行之后

      3、首屏渲染完成后

      关于 APP 启动时间,主要由 pre-main 和 main 之后的时间组成,即总的启动时间 = main 之前加载的时间 + main 之后加载的时间。启动时间越接近 400ms 越好,并且最好控制在 20s 以内,不然系统会以为 APP 进入一个死循环,应用进程将会被系统强制杀除。

      下面我们继续分别说一说这三个阶段系统都做了什么事情。

     main()函数执行前

      在main()函数执行前,系统主要会做下面几件事:

    1. 加载可执行文件(APP的.o文件的集合),就是Mach-o文件,这个在后面会详细介绍
    2. 加载动态链接库,进行rebase指针调整和bind符号绑定
    3. 运行时的初始化工作,包括类的注册,category注册,selector唯一性的检查等
    4. 执行+load()方法,attribute((constructor)) 修饰的函数的调用,创建 C++ 静态全局变量
      pre-main的加载时间,可以通过添加环境变量DYLD_PRINT_STATISTICS的方式打印出来  

     

      运行的时候就可以打印出详细的pre-main的时间 

      

      可以看到main()方法之前的时间由dylib loading ,rebse/binding,ObjC setup和initializer四个耗时的部分组成。

      所以,相对应这个阶段,我们可做的优化工作如下:

    • 减少动态库加载。每个库本身都有依赖,系统会递归的加载所有依赖的动态库,所以苹果公司建议,尽量使用更少的动态库
    • 减少无用的类、分类和方法
    • +load()方法中的内容如非必要,可以放到首屏渲染完成之后再执行,或者放在+initialize() 方法中执行。因为一个+load()方法会带来4毫秒的消耗
    • 控制C++ 静态全局变量的数量

     main()函数执行后

      main()函数执行后,是指从main()函数开始,到appDelegate 的 didFinishLaunchingWithOptions 方法里首屏渲染相关方法执行完成的过程。

      这个过程主要包括了:

    1. 日志、统计
    2. 配置APP运行需要的环境
    3. 第三方SDK初始化

      代码中,各种各样的初始化工作,全部都放在这个阶段去执行了,导致渲染缓慢。这里我们能做的优化工作是,从功能上梳理出来,到底哪些才是首屏渲染必要的初始化功能,哪些是APP启动必要的初始化功能,其他只需要在对应模块功能使用前才需要初始化的工作,分别放在他们对应的合适的位置。

      除此之外,使用 instrument 可以帮助我们进行分析didFinishLaunchingWithOptions中的耗时操作。

     首屏渲染完成后

      到这个阶段,用户已经看到我们APP的首页,这个阶段,所做的事情是其他业务模块的一些初始化工作,也就是appDelegate 的 didFinishLaunchingWithOptions 方法作用域结束的位置。

      所以这个阶段的优化优先级比较低,但是还是要注意,那些会阻塞主线程的操作,以防影响用户后面的操作。

     优化工作

      动态库加载方面

      因为主要的动态库都是系统的动态库,而系统本身对其都有相应的优化处理,所以我们能做的只有去掉无用的系统动态库,或者一步到位直接删除掉Link Binary With Libraries中的所有系统动态库,改为自动link系统动态库

      方法级别的优化

      完成了功能级别的优化后,APP的启动速度应该已经有了一定程度的缩短,下面我们再继续从方法级别去做优化。

      删除无用代码

      当我们的项目日渐壮大,业务线交错的时候,也许已经有了很多无用的冗余代码在里面,我们可以使用AppCode分析检测项目代码。

      检测完就需要手动移除无用代码了,但是注意检测结果并不十分准确,比如可能存在一些runtime映射的方法,也会被检测到,所以还是要人工再检查一遍,以防误删有用代码。

      抽象重复代码

      1、在iOS代码中可能会为同一个类写很多分类方法,由于参与开发同学较多,可能会导致方法重复,但是实际上运行起来只能有一个分类的方法被调用,这取决于哪个分类后被加载,然而编译的二进制代码中,两个方法应该是都存在的,这不仅会增加app体积,也会增加启动时间,所以应该杜绝这样的重复问题;

      2、有很多地方可能是名字不同,但是函数的功能相同,这个不容易被发现,需要大家在写代码的过程中注意;

      3、又或者两个函数名字比较接近,里面有很多相似的代码,这种情况下可以进行相同的代码的提取。

  • 相关阅读:
    HDU 5883 F
    关于codeblock 为什么不能调试
    Codeforces Round #378 (Div. 2) D. Kostya the Sculptor 分组 + 贪心
    51NOD 区间的价值 V2
    NYOJ 42 一笔画问题
    如何对二维字符数组进行排序
    hihoCoder 1383 : The Book List 北京网络赛
    利用IDA学习一个简单的安卓脱壳
    iOS APP可执行文件的组成
    Mac10.11 搭建php开发环境
  • 原文地址:https://www.cnblogs.com/xjf125/p/13896265.html
Copyright © 2020-2023  润新知