移动性能优化调研
前言
随着移动互联网的发展,产品的更新迭代,公司业务的不断扩展,移动应用页面布局也越来越复杂,效果越来越炫,自身业务功能越来越多,同时可能还接入了大量三方的SDK,随之而来的是应用程序安装包越来越大,界面数据加载和运行速度越来越低,当界面响应时间超出用户能容忍的时间临界点后,大多数用户都会选择强制关闭该应用,不再等待响应,应用给用户留下了性能很差的印象后,将会大大减低用户的使用率或寻找其他替代产品。
本次移动性能调研以SDK接入为基础着重调研以下几个方面:
- 电池耗电量
- 网络流量
- 手机发热情况
- 内存消耗量
- App启动时间过长
- App包体积
一、电池耗电
1.原因分析
- 持续的驱动设备的GPS定位、蓝牙、相机、闪光灯等造成的持续耗电
- 持续的网络传输,尤其是非Wifi环境造成的持续耗电
- 持续的高频度使用CPU/GPU、内存(例如长时间看视频、做图像处理等)造成的持续耗电
2. 代码层面分析
- 在满足需求情况下,减少GPS定位,蓝牙、相机、闪关灯等硬件的使用
- 在满足需求情况下,减少集中网络传输的情况
- CPU/GPU部分
- 注意线程、定时器以及高开销对象的使用
- 优化算法和逻辑流程,减轻CPU负荷
- 图片圆角、图片切割等处理
- 避免频繁刷新整个页面,尽量局部刷新
- 内存部分
- 避免庞大的xib,storyBoard,尽量使用纯代码开发
- Cache(缓存所有需要的)
- 服务器相应结果的缓存(图片)
- 复杂计算结果的缓存(UITableView的行高)
- 懒加载和重用
- 合理使用NSDateFormatter 和 NSCalendar这种高开销对象
3. 参考文章
- Instruments — Energy Log
- https://developer.apple.com/library/content/documentation/Performance/Conceptual/EnergyGuide-iOS/MonitorEnergyWithInstruments.html
- https://github.com/ChenYilong/iOSBlog/issues/10#%E7%B3%BB%E7%BB%9F%E6%8E%A5%E5%8F%A3
- http://www.jianshu.com/p/4555704f9696
二、网络流量
1. 原因分析
- 程序缓存机制不够完善,频繁的请求相同数据造成的流量消耗
- API设计造成的接口冗余,发起多次请求引起的流量消耗
- 使用臃肿的数据交互格式,交互数据未压缩造成的流量消耗
- 图片过大造成的流量消耗
- 针对不同网络环境没有针对性策略造成的网络消耗
2. 代码层面分析
- 避免网络请求
- 数据缓存,最快的请求就是不请求。网络通信的延迟是不可以避免的,但是对于已经请求过的数据请务必缓存下来,在下次再次访问时直接从本地获取。这样不仅能让用户有更流畅的操作,即使是在断网的情况下也能使用APP。
- 减少请求次数,合并请求
- API设计,App与Server之间的API设计要考虑网络请求的频次, 资源的状态等. 以便App可以以较少的请求来完成业务需求和界面的展示。例如, 注册登录. 正常会有两个API, 注册和登录, 但是设计API时我们应该给注册接口包含一个隐式的登录. 来避免App在注册后还得请求一次登录接口。
- 减小请求带宽
- 文本
- 数据交互格式,考虑使用Protocol Buffer代替JSON
- GZIP压缩,GZIP压缩一般对纯文本内容可压缩到原大小的40%,这样可以有效减少服务器带宽占用,提高我们我们的请求速度。
- 图片
- 图片格式 WebP格式图片的体积要比JPEG格式图片小40%
- 图片size 请求需求合适大小的Size
- 音视频等其他
- 文本
- 使用不同策略&&弱网优化
- 使用不同策略:现在2G,3G,4G网络并存,网络速度差距也很大,针对每种网络应该有不同的应对策略。比如2G网络不自动打开图片,3G,4G网络询问是否播放视频等。
- WiFi下下载离线包
3. 参考文章
- Instruments — Network
- https://blog.wilddog.com/?p=974
- http://blog.lmj.wiki/2016/10/06/app-opti/app_opt_network/
- http://www.jianshu.com/p/3a2fb50961af
- 流量监测:http://www.jianshu.com/p/7fde04cb4459
三、手机发热
1. 原因分析
- 高频率、长时间的使用手机CPU、GPU、内存、GPS、蓝牙、相机、闪光灯等等消耗大的硬件时造成短时间内大量做功引起的热量散发引起
- 手机电池在高负荷工作放掉一部分电以后,持续高负荷工作导致内阻增大、继续放电导致电池发热
2. 代码层面分析
- CPU/GPU部分
- 注意线程、定时器以及高开销对象的使用
- 优化算法和逻辑流程,减轻CPU负荷
- 图片圆角、图片切割等处理
- 频繁刷新整个页面
- 内存部分
- 避免庞大的xib,storyBoard,尽量使用纯代码开发
- Cache(缓存所有需要的)
- 服务器相应结果的缓存(图片)
- 复杂计算结果的缓存(UITableView的行高)
- 懒加载和重用
- 合理使用NSDateFormatter 和 NSCalendar这种高开销对象
- 其他
- 定位,蓝牙、相机、闪光灯按需取用,使用之后要关闭或降低频率
3. 参考文章
四、内存
1. 原因分析
- 内存管理是程序设计中很重要的一部分,程序在运行的过程中消耗内存,运行结束后释放占用的内存。如果程序运行时一直分配内存而不及时释放无用的内存,会造成这样的后果:程序占用的内存越来越大,直至内存消耗殚尽,程序因无内存可用导致崩溃,这样的情况我们称之为内存泄漏。
2. 代码层面分析
- 避免对象的循环引用和内存泄露
- 避免过于庞大的IB
- 重用和延迟加载(lazy load) Views
- 重用或少用大开销对象
- 使用Autorelease Pool
- image加载方式
3. 参考文章
- Instruments — Leaks && Allocations
- https://github.com/mindsnacks/MSLeakHunter 开发中检测内存开源库 MLeaksFinder (工具类,低耦合,泄露直接断言)
- http://www.cnblogs.com/chglog/p/4921860.html
- https://github.com/Split82/iOSMemoryBudgetTest 测试占用内存上限Demo
- https://stackoverflow.com/questions/5887248/iOS-app-maximum-memory-budget 内存上限讨论
- https://mp.weixin.qq.com/s?__biz=MjM5NTIyNTUyMQ==&mid=447105405&idx=1&sn=054dc54289a98e8a39f2b9386f4f620e&scene=0#wechat_redirect
五、App启动时间
App启动分为热启动和冷启动
- Warm launch: App和数据已经在内存中
- Cold launch: App和数据不在内核缓冲存储器中
冷启动(Cold launch)耗时才是我们需要测量的重要数据,为了准确测量冷启动耗时,测量前需要重启设备。
1. 原因分析
1.1App启动时间
App总启动时间 = t1(main()之前的加载时间) + t2(main()之后的加载时间)。
t1 = 系统dylib(动态链接库)和自身App可执行文件的加载;
t2 = main方法执行之后到AppDelegate类中的didFinishLaunchingWithOptions方法执行结束前这段时间,主要是构建第一个界面,并完成渲染展示。
1.2 App启动过程
- 链接并加载Framework和static lib
- UIKit初始化 应用程序callback
- 第一个Core Animation transaction
2. 代码层面分析
2.1 T1部分
- 减少不必要的framework,因为动态链接比较耗时
- 删除无用类,无用函数,无用变量, 可以使用工具AppCode的代码检查功能
- 将不必须在+load方法中做的事情延迟到+initialize中
- 尽量不要用C++虚函数(创建虚函数表有开销)
2.2 T2部分
- 不使用xib,直接视用代码加载首页视图
- 每次用NSLog方式打印会隐式的创建一个Calendar,因此需要删减启动时各业务方打的log,或者仅仅针对内测版输出log
- 梳理应用启动时发送的所有网络请求,是否可以统一在异步线程请求
3. 参考文章
- Instruments — Time Profiler
- http://blog.csdn.net/yangxt/article/details/8173412
- http://www.cocoachina.com/ios/20170731/20071.html WWDC笔记 T1 T2分析
- http://www.jianshu.com/p/c1734cbdf39b 实践
- https://techblog.toutiao.com/2017/01/17/iosspeed/ 今日头条博客
- https://122.226.73.189/topics/6616
- https://mp.weixin.qq.com/s?__biz=MzAwNTI4NzIxMQ==&mid=2651473464&idx=1&sn=19895882b210889aa977e9bb54b05d11&chksm=80e01a7cb797936a60cc1cfc7b2ec18afeb40d0491427abe2c426c54e0370819c9b405ac084f&mpshare=1&scene=23&srcid=1117fukoLmDc73ROB6yJ0gUM#rd
##六、包体积
###1. 原因分析
- 业务代码越来越多
- 更多的第三方库
- 更多图片或其他资源
2. 代码层面分析
- ImageOptim对图片进行压无损缩优化
- 二进制包优化,对编译后文件进行分析,查看各个文件的大小,有针对性有取舍的进行优化
- 编译选项优化 如果项目是很早之前(xcode4,5)建立的,迭代到现在 的确可以检查一下有利于减少安装包的编译选项:
- Optimization Level 使用Fastest, Smalllest 该选项对安装包大小影响几无,但可以提高app的性能。参考wwdc 2013-Session408 Optimize Your Code Using LLVM
- Strip Linked Product 设置为YES 需要注意的是Strip Linked Product也受到Deployment Postprocessing设置选项的影响。在Build Settings中,我们可以看到, Strip Linked Product是在Deployment这栏中的,而Deployment Postprocessing相当于是Deployment的总开关。记得把Deployment Postprocessing也设置为YES, 该选项对安装包大小的影响非常大, 以头条客户端为例,如果不开启此设置,ipa大小是48MB,上线后appstore上显示的大小是65MB, 我们开启了此配置后,ipa大小变成40MB, appstore上显示45MB。 优化效果还是非常明显的。 PS:Deployment Postprocessing这个配置项如果使用xcode打包,xcode会默认把这个变量置为YES, 如果使用脚本打包,记得设置。
- Symbols Hidden by Default设置为YES
- Make Strings Read-Only 设置为YES
3. 参考文章
- https://github.com/huanxsd/LinkMap 检查每个类的二进制文件大小
- https://techblog.toutiao.com/2016/12/27/iphone/ 今日头条博客
- https://blog.cnbang.net/tech/2544/
- http://www.zoomfeng.com/blog/ipa-size-thin.html
- http://www.cocoachina.com/ios/20151211/14562.html iOS微信安装包瘦身
七、其他
1.App性能分析开发商
博睿,听云,OneAPM,阿里百川码力APM
2. 其他文章
- http://www.bijishequ.com/detail/435836?p= instruments使用教程
- https://github.com/aozhimin/iOS-Monitor-Platform 性能监控SDK开发笔记
- https://github.com/Shmoopi/iOS-System-Services 开源性能分析Demo