ios动画

iOS核心动画高级技巧--(十二)性能调优

2017-11-21  本文已影响34人  努力奔跑的小男孩

在第一和第二部分,我们了解了Core Animation提供的关于绘制和动画的一些特 性。Core Animation功能和性能都非常强大,但如果你对背后的原理不清楚的话也会降低效率。让它达到最优的状态是一门艺术。在这章中,我们将探究一些动画运 行慢的原因,以及如何去修复这些问题。

CPU VS GPU

关于绘图和动画有两种处理的方式:CPU(中央处理器)GPU(图形处理器)。在现代iOS设备中,都有可以运行不同软件的可编程芯片,但是由于历史原因,我们可以说CPU所做的工作都在软件层面,而GPU在硬件层面。

总的来说,我们可以用软件(使用CPU)做任何事情,但是对于图像处理,通常用硬件会更快,因为GPU使用图像对高度并行浮点运算做了优化。由于某些原因, 我们想尽可能把屏幕渲染的工作交给硬件去处理。问题在于GPU并没有无限制处理 性能,而且一旦资源用完的话,性能就会开始下降了(即使CPU并没有完全占用)
大多数动画性能优化都是关于智能利用GPUCPU,使得它们都不会超出负荷。 于是我们首先需要知道Core Animation是如何在这两个处理器之间分配工作的。

动画的舞台

Core Animation处在iOS的核心地位:应用内和应用间都会用到它。一个简单的 动画可能同步显示多个app的内容,例如当在iPad上多个程序之间使用手势切换, 会使得多个程序同时显示在屏幕上。在一个特定的应用中用代码实现它是没有意义 的,因为在iOS中不可能实现这种效果(App都是被沙箱管理,不能访问别的视 图)。

动画和屏幕上组合的图层实际上被一个单独的进程管理,而不是你的应用程序。 这个进程就是所谓的渲染服务。在iOS5和之前的版本是SpringBoard进程(同时管 理着iOS的主屏)。在iOS6之后的版本中叫做 BackBoard

当运行一段动画时候,这个过程会被四个分离的阶段被打破:

但是这些阶段仅仅发生在你的应用程序之内,在动画在屏幕上显示之前仍然 有更多的工作。一旦打包的图层和动画到达渲染服务进程,他们会被反序列化来形成另一个叫做渲染树的图层树(在第一章“图层树”中提到过)。使用这个树状结构,渲染服务对动画的每一帧做出如下工作:

所以一共有六个阶段;最后两个阶段在动画过程中不停地重复。前五个阶段都在软件层面处理(通过CPU),只有最后一个被GPU执行。而且,你真正只能控制前 两个阶段:布局和显示。Core Animation框架在内部处理剩下的事务,你也控制不 了它。

这并不是个问题,因为在布局和显示阶段,你可以决定哪些由CPU执行,哪些交给GPU去做。那么改如何判断呢?

GPU相关的操作

GPU为一个具体的任务做了优化:它用来采集图片和形状(三角形),运行变换,应用纹理和混合然后把它们输送到屏幕上。现代iOS设备上可编程的GPU在这些操作的执行上又很大的灵活性,但是Core Animation并没有暴露出直接的接口。 除非你想绕开Core Animation并编写你自己的OpenGL着色器,从根本上解决硬件加速的问题,那么剩下的所有都还是需要在CPU的软件层面上完成。

宽泛的说,大多数 CALayer的属性都是用GPU来绘制。比如如果你设置图层背景或者边框的颜色,那么这些可以通过着色的三角板实时绘制出来。如果对一个 contents 属性设置一张图片,然后裁剪它 - 它就会被纹理的三角形绘制出来, 而不需要软件层面做任何绘制。

但是有一些事情会降低(基于GPU)图层绘制,比如:

CPU相关的操作

大多数工作在Core AnimationCPU都发生在动画开始之前。这意味着它不会影响到帧率,所以很好,但是他会延迟动画开始的时间,让你的界面看起来会比较迟钝。

以下CPU的操作都会延迟动画的开始时间:

当图层被成功打包,发送到渲染服务器之后,CPU仍然要做如下工作:为了显示 屏幕上的图层,Core Animation必须对渲染树种的每个可见图层通过OpenGL循环转换成纹理三角板。由于GPU并不知晓Core Animation图层的任何结构,所以必须 要由CPU做这些事情。这里CPU涉及的工作和图层个数成正比,所以如果在你的层 级关系中有太多的图层,就会导致CPU没一帧的渲染,即使这些事情不是你的应用 程序可控的。

IO相关操作

还有一项没涉及的就是IO相关工作。上下文中的IO(输入/输出)指的是例如闪存或者网络接口的硬件访问。一些动画可能需要从闪存(甚至是远程URL)来加 载。一个典型的例子就是两个视图控制器之间的过渡效果,这就需要从一个nib文件 或者是它的内容中懒加载,或者一个旋转的图片,可能在内存中尺寸太大,需要动 态滚动来加载。
IO比内存访问更慢,所以如果动画涉及到IO,就是一个大问题。总的来说,这就需要使用聪敏但尴尬的技术,也就是多线程,缓存和投机加载(提前加载当前不需 要的资源,但是之后可能需要用到)。这些技术将会在第14章中讨论。

测量,而不是猜测

于是现在你知道有哪些点可能会影响动画性能,那该如何修复呢?好吧,其实不需要。有很多种诡计来优化动画,但如果盲目使用的话,可能会造成更多性能上的问题,而不是修复。

如何正确的测量而不是猜测这点很重要。根据性能相关的知识写出代码不同于仓促的优化。前者很好,后者实际上就是在浪费时间。

那该如何测量呢?第一步就是确保在真实环境下测试你的程序。

真机测试,而不是模拟器

当你开始做一些性能方面的工作时,一定要在真机上测试,而不是模拟器。模拟器虽然是加快开发效率的一把利器,但它不能提供准确的真机性能参数。

模拟器运行在你的Mac上,然而Mac上的CPU往往比iOS设备要快。相反,Mac上的GPUiOS设备的完全不一样,模拟器不得已要在软件层面(CPU)模拟设备 的GPU,这意味着GPU相关的操作在模拟器上运行的更慢,尤其是使用 CAEAGLLayer 来写一些OpenGL的代码时候。

这就是说在模拟器上的测试出的性能会高度失真。如果动画在模拟器上运行流畅,可能在真机上十分糟糕。如果在模拟器上运行的很卡,也可能在真机上很平滑。你无法确定。

另一件重要的事情就是性能测试一定要用发布配置,而不是调试模式。因为当用 发布环境打包的时候,编译器会引入一系列提高性能的优化,例如去掉调试符号或 者移除并重新组织代码。你也可以自己做到这些,例如在发布环境禁用NSLog语 句。你只关心发布性能,那才是你需要测试的点。

最后,最好在你支持的设备中性能最差的设备上测试:如果基于iOS6开发,这意 味着最好在iPhone 3GS或者iPad2上测试。如果可能的话,测试不同的设备和iOS版本,因为苹果在不同的iOS版本和设备中做了一些改变,这也可能影响到一些性 能。例如iPad3明显要在动画渲染上比iPad2慢很多,因为渲染4倍多的像素点(为 了支持视网膜显示)。

保持一致的帧率

为了做到动画的平滑,你需要以60FPS(帧每秒)的速度运行,以同步屏幕刷新 速率。通过基于 NSTimer 或者 CADisplayLink的动画你可以降低到30FPS,而且效果还不错,但是没办法通过Core Animation做到这点。如果不保持60FPS的速 率,就可能随机丢帧,影响到体验。

你可以在使用的过程中明显感到有没有丢帧,但没办法通过肉眼来得到具体的数据,也没法知道你的做法有没有真的提高性能。你需要的是一系列精确的数据。

你可以在程序中用 CADisplayLink来测量帧率(就像11章“基于定时器的动画”中那样),然后在屏幕上显示出来,但应用内的FPS显示并不能够完全真实测量出Core Animation性能,因为它仅仅测出应用内的帧率。我们知道很多动画都在应 用之外发生(在渲染服务器进程中处理),但同时应用内FPS计数的确可以对某些 性能问题提供参考,一旦找出一个问题的地方,你就需要得到更多精确详细的数据 来定位到问题所在。苹果提供了一个强大的Instruments工具集来帮我们做到这些。

Instruments

InstrumentsXcode套件中没有被充分利用的一个工具。很多iOS开发者从没用过Instruments,或者只是用Leaks工具检测循环引用。实际上有很多Instruments工 具,包括为动画性能调优的东西。

你可以通过在菜单中选择Profile选项来打开Instruments(在这之前,记住要把目标设置成iOS设备,而不是模拟器)。然后将会显示出图12.1(如果没有看到所有 选项,你可能设置成了模拟器选项)。

Instruments工具选项窗口.png

我们将讨论如下几个工具:

时间分析器

时间分析器工具用来检测CPU的使用情况。它可以告诉我们程序中的哪个方法正在消耗大量的CPU时间。使用大量的CPU并不一定是个问题 - 你可能期望动画路径对CPU非常依赖,因为动画往往是iOS设备中最苛刻的任务。

但是如果你有性能问题,查看CPU时间对于判断性能是不是和CPU相关,以及定位到函数都很有帮助。

时间分析器有一些选项来帮助我们定位到我们关心的的方法。可以使用左侧的复选框来打开。其中最有用的是如下几点:

Core Animation

Core Animation工具用来监测Core Animation性能。它给我们提供了周期性的 FPS,并且考虑到了发生在程序之外的动画。

Core Animation工具也提供了一系列复选框选项来帮助调试渲染瓶颈:

这些高亮图层的选项同样在iOS模拟器的调试菜单也可用(下图)。我们之前 说过用模拟器测试性能并不好,但如果你能通过这些高亮选项识别出性能问题出在 什么地方的话,那么使用iOS模拟器来验证问题是否解决也是比真机测试更有效 的。

iOS模拟器中Core Animation可视化调试选项.png
OpenGL ES驱动

OpenGL ES驱动工具可以帮你测量GPU的利用率,同样也是一个很好的来判断和GPU相关动画性能的指示器。它同样也提供了类似Core Animation那样显示FPS的工具。

其中和Core Animation性能最相关的是如下几 点:

总结

在这章中,我们学习了Core Animation是如何渲染,以及我们可能出现的瓶颈所在。你同样学习了如何使用Instruments来检测和修复性能问题。

iOS核心动画高级技巧--目录

上一篇 下一篇

猜你喜欢

热点阅读