iOS App 启动优化
简介: 作为程序猿来说,“性能优化”是我们都很熟悉的词,也是我们需要不断努⼒以及持续进⾏的事情;其实优化是⼀个很⼤的课题,因为细分来说的话有⼤⼤⼩⼩⼗⼏种优化⽅向 ,但是切忌在实际开发过程中不能盲⽬的 为了优化⽽优化,这样有时可能会造成适得其反的负效果,需要我们根据实际场景以及业务需求进⾏合理优 化。接下来进⼊正题,本⽂将会以iOS App的启动优化为展开点进⾏探讨。
前言
作为程序猿来说,“性能优化”是我们都很熟悉的词,也是我们需要不断努⼒以及持续进⾏的事情;其实优化是⼀个很⼤的课题,因为细分来说的话有⼤⼤⼩⼩⼗⼏种优化⽅向 ,但是切忌在实际开发过程中不能盲⽬的 为了优化⽽优化,这样有时可能会造成适得其反的负效果,需要我们根据实际场景以及业务需求进⾏合理优 化。接下来进⼊正题,本⽂将会以iOS App的启动优化为展开点进⾏探讨。
启动流程:
iOS App 的启动我们都知道分为 为pre-main 和 main() 两个阶段,并且在这两个阶段中,系统会进 ⾏⼀系列的加载操作,过程如下:
1、pre-main阶段
1. 加载应⽤的可执⾏⽂件
2. 加载dyld动态连接器
3. dyld递归加载应⽤所有依赖的动态链接库dylib
2、main()阶段
1. dyld调⽤ main()
2. 调⽤UIApplicationMain()
3. 调⽤applicationWillFinishLaunching
4. 调⽤didFinishLaunchingWithOptions
阶段优化项
1、pre-main阶段
针对 pre-main 阶段做优化时,我们需要先详细了解其加载过程,这个可以在2016年WWDC 的 Optimizing App Startup Time 中详细了解到, 相关材料
1.1 Load dylibs
这⼀阶段dyld会分析应⽤依赖的 dylib (xcode7以后.dylib已改为名.tbd),找到其 mach-o ⽂件,打开和读取这些⽂件并验证其有效性,接着会找到代码签名注册到内核,最后对 dylib 的每⼀个 segment 调⽤ mmap()。不过这⾥的 dylib ⼤部分都是系统库,不需要我们去做额外的优化。
优化结论:
1、尽量不使⽤内嵌的dylib,从⽽避免增加 `Load dylibs`开销 2、合并已有的dylib和使⽤静态库(static archives),减少dylib的使⽤个数 3、懒加载dylib,但是要注意dlopen()可能造成⼀些问题,且实际上懒加载做的⼯作会更多 |
1.2 Rebase/Bind
在dylib的加载过程中,系统为了安全考虑,引⼊了ASLR (Address Space Layout Randomization)技术和 代码签名。由于ASLR的存在,镜像(Image,包括可执⾏⽂件、 dylib和bundle)会在随机的地址上加载,和 之前指针指向的地址(preferred_address)会有⼀个偏差(slide), dyld需要修正这个偏差,来指向正确的 地址。 Rebase在前, Bind在后, Rebase做的是将镜像读⼊内存,修正镜像内部的指针,性能消耗主要在 IO。 Bind做的是查询符号表,设置指向镜像外部的指针,性能消耗主要在CPU计算。
优化结论:
在此过程中,我们需要注意的是尽量减少指针数量,⽐如: 1. 减少ObjC类(class)、⽅法(selector)、分类(category)的数量 2. 减少C++虚函数的的数量(创建虚函数表有开销) 3. 使⽤ Swift struct (内部做了优化,符号数量更少) |
1.3 Objc setup
⼤部分ObjC初始化⼯作已经在Rebase/Bind阶段做完了,这⼀步dyld会注册所有声明过的ObjC类,将分类插 ⼊到类的⽅法列表⾥,再检查每个selector的唯⼀性。
在这⼀步倒没什么优化可做的, Rebase/Bind阶段优化好了,这⼀步的耗时也会减少。
1.4 Initializers
在这⼀阶段, dyld开始运⾏程序的初始化函数,调⽤每个Objc类和分类的+load⽅法,调⽤C/C++ 中的构造器 函数(⽤attribute((constructor))修饰的函数),和创建⾮基本类型的C++静态全局变量。 Initializers阶段执⾏ 完后, dyld开始调⽤main()函数。
优化结论:
1. 少在类的+load⽅法⾥做事情,尽量把这些事情推迟到+initiailize 2. 减少构造器函数个数,在构造器函数⾥少做些事情 3. 减少构造器函数个数,在构造器函数⾥少做些事情 |
2、main()阶段
在这⼀阶段⾥,主要优化重点放在 SDK初始化、业务⼯具注册、整体
didFinishLaunchingWithOptions ⽅法中,因为我们的⼀些第三⽅ app ⻛格配置、启动引导⻚显示状态逻辑、版本更新逻辑等等基本⽅都会在这⾥进⾏,如果这部分逻辑没有做好优化梳理,随着业务不断拓展,臃肿的业务逻辑会直接导致启动时 间加⻓。
在满⾜业务需求的前提下,尽量减少 didFinishLaunchingWithOptions ⽅法在主线程中的事件处理逻辑, ⽐如: 1. 根据实际业务状况,梳理各个⼆⽅/三⽅库,找到可以延迟加载的库,做延迟加载处理,⽐如放到⾸⻚控制器 的viewDidAppear⽅法⾥。 2. 梳理业务逻辑,把可以延迟执⾏的逻辑,做延迟执⾏处理。⽐如检查新版本、注册推送通知等逻辑 3. 避免进⾏⼀些复杂/多余的计算逻辑,这类逻辑尽量进⾏异步延迟处理 4. 避免在⾸⻚控制器的viewDidLoad和viewWillAppear做太多容易阻塞主线程的事情,这2个⽅法执⾏完, ⾸⻚控制器才能显示 |
场景补充:
另外,在我们实际开发过程中,很多项⽬的⾸⻚控制器都会有⼀些后台可配、较为丰富的结构或者推荐数据 进⾏展示,⽽且我们的⾸⻚展示速度通常也会被纳⼊启动优化的⼀部分,其实对于这种类型的优化,如果我 们还只是⽤传统的 api -> data -> UI ⽅式进⾏的话,就很难有明显的改善空间,因为⽤户的⽹络状态 并不是可控项,如果不做其他处理的话,那在很多场景下对⽤户来说,即使我们放上⼀些占位图,展示的样式也是很不友好的,毕竟⾸⻚控制器对⽤户的第⼀视觉冲击影响还是⽐较⼤的。
对于这种场景下的优化来说,⼀般我们可以采取 Local + Network + Update 的⽅式在⼀定程度上优化 ⾸⻚加载速度: 即:
1、 app更新过程中,⾸先进⾏本地内嵌处理逻辑,内嵌⾸⻚数据结构( localDataBase)、内嵌⾸⻚样式所需 资源( localStorage) 2、在安装启动之后,对本地与线上数据更新记录进⾏对⽐,检测是否需要更新本地内嵌数据结构 3、检测到有需要更新的数据时,才会对指定结构进⾏静默更新,并且同步更新本地数据结构 |
这样做的好处是:
1、⾸⻚数据直接从本地加载,减少⽹络数据等待时间 2、仅检测数据key值变化,⼩数据量对⽐定向更新结构,减少api数据交互频次及数据包体积 3、能够保证⾸⻚对于⽤户来说会⼀直处于⼀个友好的展示状态 |
当然这种也并不是唯⼀的应对⽅式,⽽且也并⾮对所有场景都适⽤,只是提供⼀种思路⽽已,还是需要根据 项⽬的实际场景选择适合的优化⽅案。
统计时⻓
另外如果在开发过程中,我们想直观的查看 app 启动期间,各阶段的耗时情况,也可以在Xcode,的 edit scheme 设置添加 DYLD_PRINT_STATISTICS 为1 ,打印启动时⻓,例如
优化前启动时⻓:
优化后启动时⻓:
当然,这些log我们仅仅只能在开发调试阶段查看打印,那么在实际项⽬中,我们需要对线上项⽬的启动数据 进⾏监控,以便及时的定位和优化那些影响 app 启动时⻓的环节,这时我们应该怎样更好的处理呢?
当然我们可以通过服务器埋点上报的⽅式⾃⾏统计分析,不过这样⼀来会发现我们的统计成本就会⼤⼤增 加,⽽且结果分析也会变得不那么灵活。所以这⾥推荐⼀种简单的监控⽅式,那就是友盟的 U-APM 应能性 能监控SDK ,只需要我们进⾏简单的pod集成之后,便可根据我们的实际需要进⾏⼿动或者⾃动监控启动数 据,详情可以参考 U-APM, 并且为了⽅便我们对数据进⾏分析,友盟后台已经根据这些数据帮我们绘制出 了对应的分布图,我们可以⼀⽬了然的得出启动耗时分布、启动类型占⽐等等,如图:
除此之外,我们还可以通过SDK进⾏崩溃分析、 ANR分析、监控告警、卡顿分析、内存分析等等诸多功能, 有了 U-APM 这个监控平台,其实在实际开发过程中很⼤程度的提升了我们对线上 app 的优化分析效率。
当然本⽂的介绍也只是⽐较浅显的优化项,仅供参考以及思路引导,优化之路任重⽽道远,还需要我们不断 的去探索、发现、提⾼。不过最后还是要提醒⼀句:在实际项⽬开发过程中,不要为了优化⽽优化,要根据 项⽬情况有针对性的进⾏优化。
参考:
wwdc2016optimizingappstartuptime.pdf
作者:武玉宝
原文链接
本文为阿里云原创内容,未经允许不得转载。
iOS App 启动优化的更多相关文章
- 马蜂窝 iOS App 启动治理:回归用户体验
增长.活跃.留存是移动 App 的常见核心指标,直接反映一款 App 甚至一个互联网公司运行的健康程度和发展动能.启动流程的体验决定了用户的第一印象,在一定程度上影响了用户活跃度和留存率.因此,确保启 ...
- 一触即发 App启动优化最佳实践
一触即发 App启动优化最佳实践 本文在 DiyCode 和 CSDN个人博客 同时首发,关注作者的 DiyCode帐号 或者 作者微博 可第一时间收到新文章推送. 文中的很多图都是Google性能优 ...
- Android性能优化系列之App启动优化
Android性能优化系列之布局优化 Android性能优化系列之内存优化 Android性能优化系列之apk瘦身 应用的启动速度缓慢是我们在开发过程中常常会遇到的问题,比方启动缓慢导致的黑屏.白屏问 ...
- iOS App 启动性能优化
1. App启动过程 解析Info.plist 加载相关信息,例如如闪屏 沙箱建立.权限检查 Mach-O加载 如果是胖二进制文件,寻找合适当前CPU类别的部分 加载所有依赖的Mach-O文件(递归调 ...
- IOS (APP 启动 相应处理)
APP 每次启动的入口都是通过: - (BOOL)application:(UIApplication *)application didFinishLaunchingWithOptions:(NSD ...
- Android性能优化-App启动优化
原文地址:https://developer.android.com/topic/performance/launch-time.html#common 通常用户期望app响应和加载速度越快越好.一个 ...
- iOS APP启动广告实现方式 与 APP唤端调用
APP启动广告功能实现要从2个方面思考 一是UI方案,怎样处理广告页与主页之间的切换方式. 二是广告页展示时机,是使用后台实时广告数据还是使用本地缓存广告数据.后台数据方式获取广告最新但是用户要等待后 ...
- appium + java + WebDriverAgent实现IOS app启动
Appium v1.8.1 <dependency> <groupId>io.appium</groupId> <artifactId>ja ...
- iOS app性能优化的那些事
iPhone上面的应用一直都是以流畅的操作体验而著称,但是由于之前开发人员把注意力更多的放在开发功能上面,比较少去考虑性能的问题,可能这其中涉及到objective-c,c++跟lua,优化起来相对 ...
- iOS App 性能优化总结
今天简单总结一些clientapp 优化的方案和方向. 我相信开发一个app大部分团队都能够完毕,可是性能久不一样啦,和我们都写一个冒泡算法一样,我相信每一个人写的冒泡算法都不一样,这些区别就带来了性 ...
随机推荐
- MyBatis Java 和 Mysql数据库 数据类型对应表
类型处理器(typeHandlers) MyBatis 在设置预处理语句(PreparedStatement)中的参数或从结果集中取出一个值时, 都会用类型处理器将获取到的值以合适的方式转换成 Jav ...
- TomCat 的 Jenkins 提示:你的容器没有使用UTF-8解码URL地址
1.编辑 Linux 系统的 Tomcat 安装目录的 conf 目录的 server.xml 文件 2.在 <Connector> 追加内容 URIEncoding="UTF- ...
- 3D渲染慢,直接买显卡还是用云渲染更划算?
3D渲染对建筑师和设计师来说并不陌生,3D渲染的过程中出现渲染卡顿.特殊材质难以渲染,或者本地配置不足.本地渲染资源不够时,常常会影响工作效率.本文比较了3D渲染时,为提高工作效率,买显卡还是用云渲染 ...
- 3DCAT v2.1.3新版本发布,这三大功能更新你不容错过!
3DCAT实时渲染云在近期发布了新的公有云v2.1.3的版本,本次主要更新了应用页的三项功能「语音交互设置」.「多点触控」.「音频信号位深」. 小编将对这三项更新进行讲解: 1. 调整语音通讯机制 新 ...
- Flutter Chanel通信流程
目录介绍 01.flutter和原生之间交互 02.MethodChanel流程 03.MethodChanel使用流程 04.MethodChanel代码实践 05.EventChannel流程 0 ...
- 记录--前端换肤方案 - element+less无感换肤(无需页面刷新)
这里给大家分享我在网上总结出来的一些知识,希望对大家有所帮助 前端换肤方案 - element+less无感换肤(无需页面刷新) 前言 前不久在改造一个迭代了一年多的项目时,增加了一个换肤功能.通过自 ...
- C++ Qt开发:QProcess进程管理模块
Qt 是一个跨平台C++图形界面开发库,利用Qt可以快速开发跨平台窗体应用程序,在Qt中我们可以通过拖拽的方式将不同组件放到指定的位置,实现图形化开发极大的方便了开发效率,本章将重点介绍如何运用QPr ...
- 如何使用 JavaScript 导入和导出 Excel
前言 在现代的Web应用开发中,与Excel文件的导入和导出成为了一项常见而重要的任务.无论是数据交换.报告生成还是数据分析,与Excel文件的交互都扮演着至关重要的角色.本文小编将为大家介绍如何在熟 ...
- 基于logisim-D触发器设计四人抢答电路
实验1:设计一个简易4人知识竞赛抢答电路,要求是: 裁判掌握一个按钮,作用是给电路复位和发出抢答开始命令;4名竞赛者各掌握一个按钮,每人对应一个指示灯,在主持人发出开始抢答命令后,哪位参赛者先按钮其对 ...
- (Nosql)列式存储是什么?
首先nosql可以被理解为not only sql 泛指非关系型数据库,也就是说不仅仅是sql,所以它既包含了sql的一些东西,但是又和sql不同,并在其的基础上改变或者说扩展了一些东西. 提到nos ...