iOS UI卡顿的原因及解决方案
CPU
cpu 就是中央处理器,主要负责计算,对象创建和销毁,文本的排版,图片的格式转换,解码,图像的绘制(core graphics)
GPU
GPU 是图像处理器,主要负责纹理的渲染
显示流程
CPU计算->GPU(渲染)-> 帧缓存(前缓存和后缓存) -> 读取到视频控制器 -> 显示
屏幕成像原理
当屏幕发出垂直同步信号的时候(vsync),就代表要显示一帧了,当发出水平同步信号的时候(HSync),就代表要显示一行数据,一行一行的显示,直到显示一个屏幕
卡顿产生的原因
当我们需要显示数据的时候,首先需要 CPU 计算,当CPU计算好了之后,把数据提交给GPU渲染,当我们的屏幕发出 VSync 的时候,就代表要显示了,这时候就从缓存中拿出数据显示,当我们的GPU渲染事件太长的时候,比如渲染到一半的时候,这时候 VSync 信号过来了,而这时候并没有渲染完,而这个信号过来的时候又要显示出来,这个时候就出现了丢帧,这时候屏幕显示的还是上一帧,就形成了卡顿。而这一帧只能等下一次 VSync 信号过来才能显示
离屏渲染
On-Screen Rendering:当前屏幕渲染,在当前用于显示的屏幕缓冲区进行渲染
Off-Screen Rendering:离屏渲染,在当前屏幕以外新开辟一个缓冲区进行渲染
离屏渲染耗性能原因:
- 需要创建新的缓冲区
- 离屏渲染整个过程,需要多次切换上下文,先是从当前屏幕切换到离屏,等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,有需要将离屏上下文环境切换到当前屏幕。
触发离屏渲染:
- 光栅化:layer.shouldRasterize = YES;
- 遮罩:layer.mask
- 圆角:同时设置 layer.masksToBounds = YES ,layer.cornerRadius > 0两个条件都满足,可以使用 coreGraphics 来绘制裁剪圆角,或者 UI 直接提供圆角
- 阴影:layer.shadow,如果设置了 shadowPath 就不会产生离屏渲染。
解决方案
尽量减少 CPU GPU 资源消耗,按照1s钟60FPS的刷新来算,一秒相当于1000ms,大概每隔 16ms 就会有一次 VSync 信号
CPU 优化
- 尽量使用轻量级的对象,减少 CPU 的计算,尽量用 CALayer 替代 UIView。
- 尽量不要太频繁的调整 UIView 的属性,比如 frame ,bounds等。
- 尽量做预处理,提前算好布局,然后最后再赋值,不要频繁设置,也不再在显示的时候再计算
- 少用 autolayout ,比 frame 更加耗性能。
- 图片和imageview的大小要保证大小一致,不要让它自己缩放
- 控制线程的数量,最大并发量,不要造太多的线程
- 尽量把耗时的操作放到子线程中(文本处理,尺寸计算)
- 图片的解码,绘制,放到子线程中。可以利用 CGContextRef ,图形上下文,进行解码
GPU 优化
- 尽可能的减少视图的层级和数量。
- 尽量避免短时间内进行大量图片显示
- GPU 能处理最大纹理尺寸为 4096 X 4096,如果超过就会占用 cpu 资源进行处理。
- 减少透明的视图(alpha < 1),如果图片透明,就需要一定量的计算,不透明就设置 opaque 为 yes。比如重叠部分的计算,是需要计算的,如果不透明的话,就直接盖上去就可以了
- 尽量避免离屏渲染。
网友评论