《iOS之一起进大厂》系列-iOS如何监控界面卡顿掉帧,如何优化
学而时习之,不亦说乎
PS: 下面用模仿面试的问答模式,把相关的问题和知识点串联起来。 这样可以提高阅读体验,还可以加深记忆。
开始面试
我正在会议室等待,忽然看到一个穿着格子衬衫,大腹便便的中年男子拿着简历向我走来, 我看着他头上快要绝顶的头发,心想这肯定是个iOS开发技术牛逼闪闪的老前辈。 还好看过《iOS之一起进大厂》系列,想想现在是满腹经纶,刚紧张到提到嗓子眼的心,又按下去了,淡定从容,一点都不虚好伐,就是这么自信淡定。
小伙子,看你简历上提到,对视图的性能优化有一些了解,你可不可以先说下 图像显示相关的原理
帅气逼人的面试官您好, iOS系统中 CPU、GPU、显示器是以下面图中方式协同工作的。CPU和GPU是通过总线链接起来的,CPU 计算好显示内容提交到 GPU,GPU 渲染完成后将渲染结果放入帧缓冲区,视频控制器会按照 VSync 信号逐行读取帧缓冲区的数据,经过数模转换传递给显示器显示。 下图就是图像显示的流程:
关于CPU和GPU的分工又有以下内容:
-
CPU负责:
- 对象创建和销毁
- 对象属性调整
- 布局计算、文本的计算
- 排版、图片的格式转换和解码
- 图像的绘制
-
GPU负责:
- 纹理的渲染
- 视图的混合
- 图形的生成
既然了解图像显示的原理,那你知道IOS视图卡顿掉帧的原因吗?
标准情况下,页面滑动流畅是60FPs ,就是每一秒有60帧的画面刷新,每16.7ms(1/60秒)有一帧数据。上图两个VSync 之间的时间就是16.7ms。 如果CPU 和 GPU 加起来的处理时间超过了 16.7ms,就会造成掉帧甚至卡顿。当FPs 帧数低于30时,人的肉眼就能感觉到画面明显的卡顿。
面试官吹了下自己的头发帘,心想,小伙子不错,都回答到点子上了,那再聊的深一点,那你知道如何监控界面的卡顿吗
既然知道了造成卡顿的原因,监控卡顿的思路就有了。
- 思路一:监控一秒钟内的帧数是否经常低于或远低于 60FPs。
- 思路二:监控每一帧的时长是否超时。
思路一实现方法:用 CADisplayLinker 来计数
CADisplayLink可以以屏幕刷新的频率调用指定selector,iOS系统中正常的屏幕刷新率为60次/秒,只要在这个方法里面统计每秒这个方法执行的次数,通过次数/时间就可以得出当前屏幕的刷新率了。
思路二实现方法:通过子线程监测主线程的RunLoop,判断两个状态RunLoop的状态区域之间的耗时是否达到一定阈值。
开启子线程,实时计算这两个状态区域之间的耗时是否到达某个阀值,便能揪出这些性能杀手,假定连续6次超时50ms认为卡顿(当然也包含了单次超时300ms)
老面试官露出了满意的笑容,不过做戏做要做全套嘛,那你最后说说如何优化掉帧卡顿
图像显示的工作是由CPU和GPU协同完成的, 那么优化的方向和思路就是尽量减少他们的处理时长。
对CPU处理的优化:
- 在子线程中进行对象的创建,调整和销毁,节省一部分CPU的时间
- 在子线程中预排版(布局计算,文本计算),让主线程有更多的时间去响应用户的交互
- 对文本等异步绘制,图片编解码等内容进行 预渲染、预排版
对GPU处理的优化
- 尽量避免使用 CALayer 的 Border、corner、shadow、mask 等技术,这样能少触发离屏渲染
- 尽可能将多张图片合成为一张进行显示,减轻视图层级
面试结束
小伙子回答的不错,明天接着面试其他内容。 天呐噜,明天还有。
总结
文中主要是针对了图像原理,卡顿掉帧的原因,优化方案。
- 原理:CPU负责计算,GPU负责渲染,渲染结果放到帧缓冲区再到显示器上显示。
- 原因:CPU加GPU的处理耗时超过1/60秒时,就出现了掉帧,甚至卡顿。
- 监控:监控掉帧卡顿有两种思路,监控 时间内帧数 和RunLoop两状态间的耗时是否超过阈值。
其实对视图的优化还有很多方面,比如使用UIView的异步绘制,如何避免离屏渲染,在使用TableView 如何具体优化没有提到,这些需要另外的文章篇幅才能描述清楚。 不用全堆到一起。
坚持看到这里的同学,你们个个都是人才,我好喜欢。