Instrument
Time Profile(分析代码的执行时间,找出导致程序变慢的原因)
-
Separate by Thread
按线程分开做分析,这样更容易揪出那些吃资源的问题线程。特别是对于主线程,它要处理和渲染所有的接口数据,一旦受到阻塞,程序必然卡顿或停止响应。
-
Invert Call Tree
反向输出调用树。把调用层级最深的方法显示在最上面,更容易找到最耗时的操作。
-
Hide System Libraries
隐藏系统库文件。过滤掉各种系统调用,只显示自己的代码调用。
-
Flatten Recursion
拼合递归。将同一递归函数产生的多条堆栈(因为递归函数会调用自己)合并为一条。
-
Top Functions
找到最耗时的函数或方法。
Allocations(内存分配)
-
Category(类别)
通常是一个 Core Foundation 对象,OC类、或原始内存块(block)。
-
Persistent Bytes(净分配字节数)
当前已经分配内存但是仍然没有被释放的字节的总数。
-
Persistent(净分配数)
当前已经分配内存但仍然没有被释放的对象或内存块的数量。
-
Transient(临时分配数)
当前已经分配内存但仍然没有被释放的对象或内存块的数量。
-
Total Bytes(总分配字节数)
所有已经分配内存,而且包括已经被释放了的字节的总数。
-
Total(总分配数)
所有当前已经分配内存,包括已经被释放了的对象或内存 块的总数。
-
Transient(临时分配数)
当前和全部分配数的直方图。如上图所示当比例变化时,直方条会变颜色,Instruments 应用通常给它们标示不同的颜色来指出分配模式以便进行进一步的研 究。
Leaks检查内存泄露
-
Core Data
监测读取、缓存未命中、保存等操作,能直观显示是否保存次数远超实际需要。
-
Cocoa Layout
观察约束变化,找出布局代码的问题所在。 Network:跟踪 TCP / IP 和 UDP / IP 连接。
-
Automations
创建和编辑测试脚本来自动化 iOS 应用的用户界面测试。
Core Animation(必须使用真机)
-
Color Blended Layers(图层混合):检测哪里发生了图层混合,并用红色标记出来。需要尽可能减少或者消除红色区域。
解决方法:
1、backgroundColor属性(最重要),如果不设置这个属性,控件依然被认为是透明的
2、opaque设置为YES,作用不是很大;但如果设置NO,影响却很大
3、关闭alpha通道
注意:对于文字,iOS8上用UILabel显示中文却出现了像素混合的情况,因为在iOS8以前,UILabel使用的是CALayer作为底图层,而在iOS8开始,UILabel的底图层变成了_UILabelLayer,绘制文本也有所改变。
解决方法:背景色的四周多了一圈透明的边,而这一圈透明的边明显超出了图层的矩形区域
设置图层的masksToBounds为YES时,图层将会沿着Bounds进行裁剪,就可以了
-
Color Hits Green and Misses Red(光栅化):它表示如果命中缓存则显示为绿色,否则显示为红色,显然绿色越多越好,红色越少越好
光栅化是将一个layer预先渲染成位图(bitmap),然后加入缓存中。如果对于阴影效果这样比较消耗资源的静态内容进行缓存,可以得到一定幅度的性能提升。demo中的这一行代码表示将label的layer光栅化:label.layer.shouldRasterize = true。
光栅化的核心在于缓存的思想,因为layer进行光栅化后渲染成位图放在缓存中。当屏幕出现滑动时,我们直接从缓存中读取而不必渲染,所以会看到绿色。当新的label出现时,缓存中没有个这个label的位图,所以会变成红色。第三点比较关键,缓存中的对象有效期只有100ms,即如果在0.1s内没有被使用就会自动从缓存中清理出去。这就是为什么停留一会儿再滑动就会看到红色。
光栅化的缓存机制是一把双刃剑,先写入缓存再读取有可能消耗较多的时间。因此光栅化仅适用于较复杂的、静态的效果。光栅化会导致离屏渲染
-
Color Copied Images(颜色格式):比如应用中有一些从网络下载的图片,而GPU恰好不支持这个格式,这就需要CPU预先进行格式转化。“Color Copied Images”就用来检测这种实时的格式转化,如果有则会将图片标记为蓝色,说明图片格式出现了一些问题。
背景:像素在内存中的布局和它在磁盘中的存储方式并不相同。考虑一种简单的情况:每个像素有R、G、B和alpha四个值,每个值占用1字节,因此每个像素占用4字节的内存空间。一张1920*1080的照片(iPhone6 Plus的分辨率)一共有2,073,600个像素,因此占用了超过8Mb的内存。但是一张同样分辨率的PNG格式或JPEG格式的图片一般情况下不会有这么大。这是因为JPEG将像素数据进行了一种非常复杂且可逆的转化。
当我们打开JPEG格式的图片时,CPU会进行一系列运算,将JPEG图片解压成像素数据。显然这个工作会消耗不少时间,所以不应该在滑动时进行,我们应该预先处理好图片。 -
Color Misaligned Images(图片大小):它表示如果图片需要缩放则标记为黄色,如果没有像素对齐则标记为紫色。
这个优化是调整所有图片的像素大小以避免不必要的缩放。我们要尽可能保证无论是本地图片还是从网络或取得图片的大小,都与其frame保持一致。
-
Color Offscreen-Rendered Yellow(离屏渲染):离屏渲染的地方标记为黄色。离屏渲染意味着把渲染结果临时保存,等用到时再取出,因此相对于普通渲染更占用资源。
离屏渲染可能会自动触发,也可以手动触发。以下情况可能会导致触发离屏渲染:
- 重写drawRect方法
- 有mask或者是阴影(layer.masksToBounds, layer.shadow*),模糊效果也是一种mask
- layer.shouldRasterize = true
前两者会自动触发离屏渲染,第三种方法是手动开启离屏渲染。
设置cornerRadius本身并不会导致离屏渲染,但很多时候它还需要配合layer.masksToBounds = true使用。根据之前的总结,设置masksToBounds会导致离屏渲染。解决方案是尽可能在滑动时避免设置圆角,如果必须设置圆角,可以使用光栅化技术将圆角缓存起来:
// 设置圆角
label.layer.masksToBounds = true
label.layer.cornerRadius = 8
label.layer.shouldRasterize = true
label.layer.rasterizationScale = layer.contentsScale -
Color Compositing Fast-Path Blue(快速路径):用于标记由硬件绘制的路径,蓝色越多越好
离屏渲染的最后一步是把此前的多个路径组合起来。如果这个组合过程能由CPU完成,就会大量减少GPU的工作。这种技术在绘制地图中可能用到。
-
Flash updated Regions(变化区域):用于标记发生重绘的区域。 一个典型的例子是系统的时钟应用,绝大多数时候只有显示秒针的区域需要重绘:刷新视图时,我们应该把需要重绘的区域尽可能缩小,对于未发生变化的内容则不应该重绘。
总结:
优化滑动性能主要涉及三个方面:
1、避免图层混合
- 确保控件的opaque属性设置为true,确保backgroundColor和父视图颜色一致且不透明。
- 如无特殊需要,不要设置低于1的alpha值。
- 确保UIImage没有alpha通道。
2、避免临时转换
- 确保图片大小和frame一致,不要在滑动时缩放图片。
- 确保图片颜色格式被GPU支持,避免劳烦CPU转换。
3、慎用离屏渲染
- 绝大多数时候离屏渲染会影响性能。
- 重写drawRect方法,设置圆角、阴影、模糊效果,光栅化都会导致离屏渲染。
- 设置阴影效果是加上阴影路径。
- 滑动时若需要圆角效果,开启光栅化。
网友评论