《iOS 三问》 -- iOS UI 显示的原理及优化策略 (中) -- iOS UI 优化工具
工欲善其事,必先利其器。在进一步对 UI 优化进行探索之前,我们有必要一起先学习下在 iOS 性能优化中常用到的一些工具。有了上一章 iOS UI 显示基础 的学习,我们应该可以理解这些工具的用途。本章主要也是以了解为主,在下章中,我们会深入到具体的问题,运用我们学到的知识与工具具体地解决之,真正达到学有所获。
1 iOS UI 优化原则
1.1 使用真机测试,使用发布配置调试
优化首先的原则就是:当你开始做一些性能方面的工作时,一定要在真机上测试,而不是模拟器。模拟器虽然是加快开发效率的一把利器,但它不能提供准确的真机性能参数。模拟器运行在你的 Mac 上,然而 Mac 上的 CPU 往往比 iOS 设备要快。而且,Mac 上的 GPU 和 iOS 设备的完全不一样,模拟器不得已要在软件层面(CPU)模拟设备的 GPU,这意味着 GPU 相关的操作在模拟器上运行的更慢,尤其是使用 CAEAGLLayer
来写一些 OpenGL 的代码时候。
这就是说在模拟器上的测试出的性能会高度失真。如果动画在模拟器上运行流畅,可能在真机上十分糟糕。如果在模拟器上运行的很卡,也可能在真机上很平滑。你无法确定。
另一件重要的事情就是性能测试一定要用发布配置,而不是调试模式。因为当用发布环境打包的时候,编译器会引入一系列提高性能的优化,例如去掉调试符号或者移除并重新组织代码。你应该只关心发布性能,那才是你需要测试的点。
最后,最好在你支持的设备中使用性能最差的设备上测试,因为一般老的机子性能会相对弱点,如果老的机子都没问题,一般新的机子上效果就只会更好。
2 Xcode 集成 Debug 工具
2.1 Debug Navigator
Xcode 自身已经集成有非常牛逼的调试工具了,在观察一般性能问题时,我们甚至都不需要使用 instruments
。在 xCode 中调试运行 (真机或模拟器),选中左栏中的 debug
项,就可以看到集成的调试工具。
如图所示,在我当前使用的 xCode 9.3
版本中,可以在 debug
栏中查看 CPU 及内存还有磁盘 IO 等情况了 (9.3 新增了用电监测功能)。点击右上角,还可以展示一些更牛 X 的工具,如下:
在这里可以查看一些 dump 信息,比如当前 app 的 view 层级 (出现 UI 问题时特别有用),还有内存分配信息,这里特别展示一下:
在这个调试页面,你可以看当前 app 内存的分配情况,粒度是细化到对象的。可以看某个类有多少个对象实例,以及他们之间的持有关系,这样一眼就看出有没有循环引用了。
2.2 View Debuging
在工具栏的 Debug
选项中,有许多调试工具可以使用,其中的 View Debuging
对 UI 调试比较重要。
我们可以从图中看出这些工具,其中上层的 screenShot (截图)
,show view framw (以 view 加边框)
也是较常用的工具,对于界面的布局比较有用。后面的 Rendering
则是 UI 性能调试重要工具,这里着重介绍下:
2.2.1 Color Blended Layers
混合图层,名如其意,回想下我们上一篇 iOS UI 显示基础 中关于 GPU 图像合成所学到的内容,需要合成的图层超多,GPU 的工作就越重。用了这个工具,会使用绿到红的高亮来表示混合的程序,越红表示越多合成,性能自然越差。好好复习下上章的内容,将 view
或 layer
的 opaque
属性设为 YES
, 去掉视图的透明度及透明背景就可以很好地优化这个点了。
在我的 iOSOneDemo 中的示例 UI 优化 - 优化工具
中,我们打开 Color Blended Layers
,会看到如下这样,因为 Label 是透明的,会和底层的图层发生颜色合成,所以这里会显示成红色。
优化方法,我们只要有问题的视图设置为非透明就可以了,比如上例中列表中的 Label 这样设置:
1 | cell.textLabel.clipsToBounds = YES; |
你甚至可以不需要修改它的 opaque
属性,这个不透明结论会自动帮你做出 (当背景色非透明时)。如果你下载了我的 demo 的话会发现原来红色的区域不见了。
2.2.2 Color Offscreen-Rendered Yellow (离屏渲染检测器)
这个选项会把那些 离屏渲染
的图层显示为黄色。黄色越多,性能越差。这些显示为黄色的图层很可能需要用 shadowPath 或者 shouldRasterize 来优化(离屏渲染问题请看下一章 UI 优化场景 - 离屏渲染)。
在 View Debuging 示例小节我们会用实例说明。
2.2.3 Color Hits Green and Misses Red
当 UIView.layer.shouldRasterize = YES
时,耗时的图片绘制会被缓存,并当做一个简单的扁平图片来呈现(下一章 UI 优化场景 - 离屏渲染)。这时候,如果页面的其他区块 (比如 UITableViewCell 的复用) 使用缓存直接命中,就显示绿色,反之,如果不命中,这时就显示红色。红色越多,性能越差。
同样,在 View Debuging 示例小节我们会用实例说明。
2.2.4 Color Copied images
对于 GPU 不支持的色彩格式的图片只能由 CPU 来处理,把这样的图片标为蓝色。蓝色越多,性能越差。因为,我们不希望在滚动视图的时候,由 CPU 来处理图片,这样可能会对主线程造成阻塞。
2.2.5 Color Misaligned Images
这个选项检查了图片是否被缩放,以及像素是否对齐。把图片放进了与其大小不一致的 imageView 中会导致缩放。而布局定位不对的 view 会因为像素对不齐导致紫色,而像素对齐比较常见是自行进行等比缩放时结果没有取整,导致 x/y 坐标没对齐。被缩放的图片会被标记为黄色,像素不对齐则会标注为紫色。黄色、紫色越多,性能越差。
2.2.6 Color OpenGL Fast Path Blue
这个选项会把任何直接使用 OpenGL 绘制的图层显示为蓝色。蓝色越多,性能越好。如果仅仅使用 UIKit 或者 Core Animation 的 API,那么不会有任何效果。如果使用 GLKView 或者 CAEAGLLayer,那如果不显示蓝色块的话就意味着你正在强制 CPU 渲染额外的纹理,而不是绘制到屏幕。
2.2.7 Flash Updated Regions
这个选项会把重绘的内容显示为黄色。不该出现的黄色越多,性能越差。通常我们希望只是更新的部分被标记完黄色。
3 Instruments
在 Xcode 的 Product
-profile
中打开 Instruments
.
所有工具的应用都是点左上角的录制键开始录制,然后 instruments 会启动应用,这时你的 app 就在监控中了,你对 App 的监控数据如 CPU 占用率、内存使用情况、界面帧率 FPS 等都会被相应的工具记录下来。 Instruments
的使用就是这样一个录制加分析的过程,虽然使用简单并不复杂,但是功能却非常强大。下面我们来看下在 UI 性能分析上主要的工具。
3.1 Time Profiler
时间分析器工具的主要作用是用来检测 CPU 的使用情况。它可以告诉我们程序中的哪个方法正在消耗大量的 CPU 时间。使用 Time profiler
可以检测出在程序运行过程中各方法消耗的 CPU 时间,其中定位到函数的功能是非常有用的。
3.2 Core Animation FPS
Core Animation FPS 主要用于观察界面的 FPS 帧率。
4 View Debuging 示例
示例代码具体请看我的 iOSOneDemo 中的示例 UI 优化 - 优化工具
。运行界面如下:
4.1 使用 instruments 看页面流畅度与资源占用情况
我们分析问题时如果有明显的卡顿,那么一下子就说明问题了,但是如果不太明显,一开始最好还是先用 instruments 来看看页面的 CPU 占用率及 FPS 帧率。如果 CPU 占用率高,说明当前肯定做了些耗时计算,这时可以看看是否可以优化下算法或是把计算放到后台队列里去做。如果 FPS 帧掉得很厉害,就要再进一步分析看是 CPU 计算量大,还是 GPU 压力大了。
具体到这个实例,我们先分析下 FPS,发现在滑动列表时,帧率平均在 20 左右,此时 CPU 占用率不高,见下图中 CPU Usage 那一项,而 GPU 利用率高达 80%(我用红框框着的).
这样,我们就可以把问题定位在 GPU 渲染上了。
4.2 Color Blended Layers
我们使用第一节中说的 Debug 工具 Color Blended Layers
,看到界面中的透明合成也就是红色部分可以优化。
- 分析与解决
因为 Lagel 是透明背景的,我们可以将之去掉,代码修改:
1 | cell.textLabel.clipsToBounds = YES; |
点击优化控制中的 “透明层叠优化” 按钮,可以发现,红色的提示区域不见了。
4.3 离屏渲染优化
优化了 blend layer 后,发现 FPS 并没有明显的提升,现在我们怀疑还有可能是列表的图片和 Labe 使用了阴影,造成了离屏渲染了。
我们使用 Debug 工具 Color Offscreen-Rendered Yellow
,发现列表项是深黄,说明问题真的存在。
与是我们把阴影的代码去掉,深黄色的内容不见了,FPS 也上去了,GPU 占用率下降,说明问题真的得到解决。
但是如果我们还是在使用阴影效果呢?参照 UI 优化场景 - 离屏渲染 所说的使用 shouldRasterize 优化之
1 | cell.layer.shouldRasterize = YES; |
使用 Color Hits Green and Misses Red
,可以看到只有 cell 刚要绘制时出现红色,问题得到了优雅解决!
这里可以通过界面上方的 “优化控制” 显示效果就行,具体关于离屏渲染的解释和光栅化解决的原理,请下一章 UI 优化场景 - 离屏渲染 我们将学习之。
5 引用
- 【1】answerhuang - 《将像素绘制到屏幕上去》
- 【2】Nick LockWood - 《iOS Core Animation: Advanced Techniques》