携手创作,共同生长!这是我参与「日新方案 8 月更文挑战」的第27天,点击查看活动概况
本文从苹果在底层是如何烘托画面到屏幕上的进程开始,以此来进一步剖析屏幕卡顿的原理,最后进行屏幕卡顿的处理。
主要内容:
- 卡顿原理
- 卡顿优化
- 离屏烘托
1. 卡顿原理
1.1 CRT显现器原理
电子枪从上到下一行一行的扫描,扫描完结后便是一帧画面,之后就回到初始方位进行下一轮扫描,这样就完结了画面显现。 显现器每次扫描需求获取显现的数据,这样就需求与系统的视频操控器进行同步,显现器会用硬件时钟发生一系列的守时信号来进行同步。
守时信号有两种,一个是水平同步信号(HSync),一个是笔直同步信号(VSync)。
制作进程
- 预备扫描每一行都会宣布一个HSync信号
- VSync信号到来后,主线程开始在CPU中核算内容,包括创立视图、布局核算,图片解码、文本制作等,核算好的内容提交到GPU
- GPU进行变换、合成、烘托,将烘托结果放到帧缓冲区(frameBuffer)
- 视频操控器会在比及下一次VSync信号到来后逐行读取帧缓冲区的数据
- 读取完结后,进行必定的数模转化传递给显现器显现
- 简略来说便是,经过CPU的核算以及GPU的烘托之后,会将帧数据存放到帧缓存区中,之后视频操控器读取到帧缓存区的数据,经过数模转化传递给显现器显现
- 当一帧画面完结,预备画下一帧时,会宣布一个VSync
进程示意图:
留意:
- 显现器一般以固定的频率进行改写画面,也便是每帧画面完结的时刻,这个改写率便是笔直同步信号(VSync)
1.2 画面显现原理
主要了解笔直同步机制
假如只要一个帧缓冲区,帧缓冲区的读取和改写都有较大的功率问题。因此一般需求引进双缓冲机制,也便是两个帧缓冲区,GPU会预先烘托好一帧放入到帧缓冲区,视频操控区进行读取,在读取的进程中,就能够将新烘托好的一帧放到另一个帧缓冲区,这样就能够一直不断的进行改写帧缓冲区,而当视频操控器读取完结,GPU会自动的把指针指向第二个缓冲区,这样读取和改写帧缓冲区的功率都提高了。
但上面的双缓冲机制有一个很大的问题,便是GPU会一直不断的将烘托好的一帧数据放到帧缓冲区中,而且在提交完结后,会自动的把指针指向第二个缓冲区,这样假如此刻视频操控器还未读取完结,比方读取到一半,下一半就变成了下一帧的数据,就会形成画面撕裂现象。
正由于帧缓冲区的帧数据混用形成画面撕裂问题,需求引进笔直同步机制。也便是说,之前显现器只是把笔直水平信号同步到了视频操控器,笔直同步机制直接同步到了GPU
了解: GPU会等候显现器宣布笔直水平信号(VSync)后,才进行新的一帧烘托和缓冲区更新
本质: 帧缓冲区的更新和读取时一同进行,而且都收到VSync信号的操控,读取上一个帧数据时,更新下一个帧数据
1.3 卡顿(掉帧)原理
在笔直同步机制下就会呈现卡顿现象。
上面所说的笔直同步机制,需求VSync到来时,更新帧数据,下一个VSync到来时,会读取这次更新的帧数据。而假如下一个VSync到来时,由于CPU或GPU的原因,帧数据还没有更新到帧缓冲区,就会继续读取上一个帧数据,在一个VSync时刻内显现了两次帧数据,就会形成卡顿现象。
CPU和GPU都会阻止显现流程,都会形成掉帧现象
2. 卡顿优化
分为两类,CPU和GPU。
2.1 CPU资源耗费原因和处理方案
基本原则有两个:第一是避免运用不必要的操作,第二是必需的操作尽量放到后台履行。
避免不必要的操作:
- 目标创立
- 原因:目标的创立会分配内存、设置特点等操作比较耗费CPU资源,假如是反射机制就耗费的更多
- 处理:
- 运用轻量级的目标替代重量级的目标
- 推迟目标创立的时刻,并把多个目标的创立涣散到多个使命中,不要集中创立
- 假如目标能够复用,能够放到一个缓存池中复用
- 也便是说,假如用功用较少的目标能够完结使命,就不要用功用许多的目标了
- 例如:CALayer比UIVIew要轻量许多,假如不涉及事情呼应,只需求显现,就能够用CALayer来替代UIView
- 纯代码编码
- 原因:storyboard创立视图目标耗费资源会比直接运用代码创立目标要大的十分多
- 处理:能够考虑运用纯代码编码
- 目标调整
- 原因:设置特点会耗费比较多的资源,所以需求避免频频的设置特点
- 处理:尽量避免削减不必要的特点修改
- 例如:尤其是给UIView重设 特点时,比方frame时,其实都是设置了CALayer的特点,而CALayer是没有特点的,是经过办法动态解析完结的,临时为目标创立的一个特点,这十分耗费资源,所以应削减给UIView重置大小等操作
- 尽量避免调整视图层次,添加和移除视图,UIView、CALayer之间会呈现许多办法调用与告诉
- Autolayout
- 原因:关于复杂视图会发生严重的功能问题
- 处理:能够手动调整特点
必需的操作放到后台履行
- 目标毁掉
- 原因:假如很多的目标进行毁掉,也会占用必定的资源
- 处理:能够放到后台去开释目标
- 例如:在一个集合中保存有很多的目标,毁掉这个集合时就会一同毁掉这些目标,尽量放到后台去履行
- 布局核算
- 原因:视图布局的核算是最为常见的耗费CPU资源的地方
- 处理:能够在后台提早核算好视图布局,并进行缓存
- 例如:UIView的特点设置,尽量在后台核算好,一次性调整好特点
- 文本宽高核算
- 原因:文本的宽高核算会占用很大一部分资源,而且不可避免
- 处理:运用[NSAttributedString boundingRectWithSize:options:context:] 来核算文本宽高,用 -[NSAttributedString drawWithRect:options:context:] 来制作文本,而且这两个办法需求放入到后台线程履行
- 也能够高度缓存
- 文本烘托
- 原因:一切的文本内容控件在底层都是经过CoreText完结的,而它的排版和制作都是在主线程中,所以当显现很多文本的时候,CPU的压力会十分大
- 处理:在底层的CoreText对文本进行异步制作
- 图片解码
- 原因:创立图片时,图片的数据并不会立即解码,而是在提交到GPU前CGImage中的数据才会得到解码,而且是在主线程中履行,所以会发生较多的耗费
- 处理:常见的做法是,先在后台把图片制作到CGBITmapContext中,然后从bitmap直接创立图片
2.2 GPU资源耗费原因和处理方案
GPU:GPU是用图画处理器,它处理的内容都在显存中
耗费资源原因和处理方案
- 纹路的烘托
- 问题1:假如短时刻内显现很多的图片,不管是提交到显存的进程,仍是GPU进行烘托都要耗费不少GPU资源
- 处理1:尽量避免短时刻内显现很多的图片,尽可能的将多张图片合成为一张进行显现
- 问题2:当图片过大,超越GPU的最大纹路尺度,CPU会进行预处理,会对CPU和GPU带来额外的资源耗费
- 处理2:图片和视图大小不要超越纹路尺度上限(4096*4096)
- 视图的混合
- 问题:多个视图叠在一同显现,GPU会首先把他们混合到一同再烘托,假如视图结构太过复杂,在混合的进程中也就会耗费资源了
- 处理:削减视图数量和层级
- 图画制作
- 问题:CALayer的border、圆角、暗影、遮罩(mask)等显现一般会触发离屏烘托,GPU在进行离屏烘托就会耗费必定的资源
- 处理:
- 尽量运用现已设置好的图片,不必GPU去进行设置。
- 把需求显现的图形在后台线程回执未图片,避免运用圆角、暗影、遮罩等特点
3. 离屏烘托
离屏烘托是值GPU在当时屏幕缓冲区之外再开辟一个新的离屏缓冲区,进行烘托。
由于当我们烘托完图层,要进行一些操作的时候,比方设置圆角、暗影、高斯含糊等,之前存放在帧缓冲区的帧数据现已不在了,所以就需求开辟一个离屏缓冲区来存放这些中间状态的数据。
当一切的图层都烘托到离屏缓存区之后,在分别从各个离屏缓冲区取出数据,做出设置圆角等操作后,组合起来存入到帧缓冲区。
利害:
离屏烘托的价值
- 开辟新的离屏缓冲区会占用空间,会耗费资源
- 切换上下文环境也耗费许多资源
- 离屏烘托明显会比及一切的图层的操作设置好之后再喝到一同存入帧缓冲区,时刻会更久,容易呈现卡顿现象
优点:
- 关于多次呈现的数据,能够提早烘托好,达到复用的目的
- 特殊效果,需求运用离屏缓存区保存中间状态