iOS性能优化

iOS性能优化

iOS性能优化,可以从启动时间、挂起(hang)、卡顿(hitch)、内存、电池使用、硬盘读写等方面进行优化。

启动时间

启动类型

app的启动类型有三种:1.Cold;2.Warm;3.Resume;Cold启动,一般发生在手机刚开机,或者一个应用很久没有打开过的情况。Warn启动,一般是app退出不久,又重新打开的情况。Resume,是app进入后台,然后重新进入前台的情况。

Warm和Resume一般都能很快启动,Cold启动是最慢的。所以优化app的启动时间,主要是考虑Cold启动的情况。

最优启动时间

如果一个app的Cold启动时间在400ms以内,那么用户基本感觉不到卡顿,所以小于400ms是最优启动时间。

app启动阶段

Cold启动可以分为六个阶段:

  1. System Interface。这个阶段主要是dyld的工作,加载动态库的操作会影响这个阶段的时间,如果这个阶段时间过长,可以考虑移除没有使用的动态库,或者减少动态库的使用;
  2. Runtime init。这个阶段是runtime的初始化,如果在+[NSObject load]中做了事情,会消耗时间。另外过多的使用分类也会消耗时间;
  3. UIKit init。这个是固定的消耗,不需要优化;
  4. Application init。- application: didFinishLaunchingWithOptions:中的操作损耗的时间。
  5. Initial frame render。第一帧画面渲染消耗的时间。第一个页面的View的层级,自动布局,和其他的一些阻塞主线程的操作,都是影响这个阶段的时间。
  6. Extended。 不是每个app都有的阶段。一般和启动后异步加载数据有关。

所有能优化app启动时间的方法,都在上面的六个阶段里。

app启动时间测试

Instruments和XCTest都有测试app启动时间的功能,此外Metric Kit也可以统计app在用户使用时的启动时间。

卡顿(hitch)

卡顿发生在ScrollView滚动、动画效果和页面转场动画中,当你发现滚动或者动画“不怎么流畅”,那就是卡顿了。

在滚动或者动画时,对于60fps的屏幕,要求是每16.67ms显示新的一帧。如果新的一帧没有能在16.67ms内准备好,那么屏幕下一个16.67ms内显示的还是旧的那一帧,就会导致卡顿。

触发每一帧开始渲染事件的硬件叫做VSYNC,在60fps的屏幕上,VSYNC每16.67ms触发一次渲染事件,渲染事件发生后,新的一帧必须已经准备好,否则就会产生卡顿。

要解决卡顿问题,我们先要知道在滚动或者动画时,每一帧是怎么渲染的。渲染的过程,叫做Render Loop,由以下六个阶段组成:

  1. Event。这个阶段,app接受到了事件(触摸/网络回调/按压键盘/定时器等),并且做出响应。通常的响应方式有:改变图层大小/位置/颜色,甚至改变图层结构等等。

  2. Commit。处理上一阶段图层的设置,例如AutoLayout,drawRect等等。

  3. Render prepare。来到这一步,所有图层已经布局并绘制好了,Render Server在这一步为渲染成真正的图片做好准备。

  4. Render execute。渲染图片,大名鼎鼎的离屏渲染会发生在这一步。

  5. Display。图片已经完成渲染,VSYNC事件到来时就可以显示了。

根据Render loop,导致卡顿的原因可以分为两种类型:

  1. Commit hitch。表示app花了太多时间来处理Event或者Commit。

  2. Render hitch。表示花了太多时间来render。

导致Commit hitch的原因,一般是AutoLayout耗时太多,或者做了太多图层的添加或插入等改变图层的操作,或者drawRect耗时太多。

导致Render hitch的原因,一般是离屏渲染。

卡顿的检测

可以通过Instruments的Animation Hitchs或者MetricKit来检测卡顿。

挂起(hang)

用户点击屏幕后,如果用户界面超过1秒以上没有任何反应,这种情况叫做挂起(hang),就是我们平时说的“卡死了”。挂起非常影响用户体验。

发生挂起的原因

挂起的发生和主线程的runloop有关。主线程的runloop,最重要的功能,就是响应用户触摸事件,处理触摸事件,然后更新界面。如果处理触摸事件的时间过长,就会导致挂起。

导致主线程处理时间过长,主要可以分为两种原因:

  1. 主线程执行的任务太耗时。例如网络请求、IO操作、负复杂的视图布局等。
  2. 第二种是多线程环境。尤其是使用锁,信号量等,导致主线程等待。

所以主线程应该只专注于更新UI任务。

挂起的检测

开发阶段,可以使用Instruments中的Time Profile来检测挂起。发布阶段,可以使用MetricKit来检测。

挂起的修复

现在我们知道,挂起是由于主线程执行耗时任务导致的,所以挂起的修复也很明确:

  1. 对于不需要在主线程中执行的任务,放到子线程中执行;
  2. 优化必须在主线程中执行的任务,使它们更快完成。

内存

内存是有限的资源,如果过多地占用内存,会导致app卡顿,甚至有被系统终止的风险。所以,我们在开发app时,要关注我们app的内存是否过多的使用。

在开发阶段,在Xcode的Debug窗口,我们很容易就能看到app当前内存的使用情况。

Xcode Debug窗口

如果发现内存占用过高,就要考虑优化一下内存的使用了。如上图所示,当前只用了20.6MB的内存,指针在绿色区域,所以是比较健康的。如果指针在黄色或者红色区域,就要考虑优化内存了。

如果内存过高时,可以通过查看Memory Graph Hierarchy来分析内存的使用细节。

Memory Graph Hierarchy

在Xcode中查看Memory Graph Hierarchy不够灵活,我们可以把Memory Graph Hierarchy导出到一个.memgraph文件,在终端中通过vmmap、leaks、heap、malloc_history等工具对该文件进行分析。

使用vmmap获取当前 a.memgraph 文件的概览

vmmap -summary a.memgraph

使用leaks检查内存泄露:

leaks a.memgraph

使用heap显示分配在进程堆上的对象:

heap -sortBySize a.memgraph

使用malloc_history检查某个内存的创建过程:

malloc_history a.memgraph [address]

通过上面的工具,就有可能定位到导致大量内存占用的代码了。

注意图片

在iOS中,占用内存最大的对象,一般是图片!

一张590KB,尺寸为2048*1536的JPEG图片,在app中显示时,可以占用10MB的内存!因为每个像素点占4个字节,2048乘以1536然后乘以4字节,就会达到 10MB!

需要重点关注图片的尺寸,尺寸越大,占用的内存越大!其实手机的屏幕上,根本不需要太大的图片的,所以往往缩小图片的尺寸是常见的降低内存占用的手段。

缩小图片尺寸,需要用Image I/O框架,不要用UIImage的方法!因为UIImage的方法还是会先把图片解码,内存占用还是很大。

因为图片占用的内存实在太大,所以,在看不到图片的时候,最好把图片释放,等到需要展示图片的时候再加载回来。

例如,在ViewController中可以这样处理:

- (void)viewDidDisappear:(BOOL)animated {
    [super viewDidDisappear:animated];
    // 释放图片
    [self unloadImages];
}

- (void)viewWillAppear:(BOOL)animated {
    // 加载图片
    [self loadImages];
    [super viewWillAppear:animated];
}

此外,还可以通过监听UIApplicationDidEnterBackgroundNotificationUIApplicationWillEnterForegroundNotification广播,在app进入后台后释放图片,在app回到前台时加载图片。

电池使用

主要是降低app对电池的损耗。主要一下四个方面减少电量的损耗:

  1. 支持dark mode。支持dark mode是能显著减低电池损耗的方式,官方宣称可以节省70%的电池损耗!

  2. 确保使用合理的屏幕帧率。现在有些iOS设备的屏幕帧率可以去到120fps,高帧率意味着高电池消耗,其实大部分场景都不需要这么高的帧率。核心是审计屏幕上的次要内容的帧率不能高于主要内容的帧率。例如,一个很简单的页面,主要的内容使用30fps的帧率就足以显示了,但是这个页面有一个次要元素,使用了60fps的动画效果,那么这个次要元素会导致整个屏幕使用的是60fps的屏幕帧率。这种情况,需要降低整个次要元素动画的帧率为30fps,从而减少电量的消耗。

  3. 管理好后台任务。如果app使用后台定位、后台音频播放这些后台任务,就要处理好这些任务的使用情况,防止在后台持续消耗电量。

  4. 将一些非用户触发且不需要及时响应的任务延迟到适当的时候执行。例如:1. 自动下载任务(像预先缓存一些电视节目),可以使用NSURLSession的后台下载;2. 苹果推送(APNs),降低一些不重要的通知的优先级。

硬盘读写


 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值