iOS 卡顿原理及优化笔记

一、CPU和GPU的工作

相当于CPU跟GPU提出需求,我需要一个长宽高为50的箱子,并且希望在这个箱子上面刻有xxxx的文案和图案,我可以提供给你文案和图案。但是制作是由你(GPU)来完成

二、VSync信号

VSync信号是由硬件时钟生成,每秒钟发出60次,当两次VSync信号到达之间(16.7ms
),如果帧缓冲区的数据(FrameBuffer)没有发生改变(要么是CPU过载数据计算没有及时更新、要么是GPU过载,渲染没有完成)时,就会发生卡顿掉帧

三、卡顿优化:

1、CPU

1).尽量用轻量级对象,比如开发中常用到的UIView或者圆角处理,在不需要用到事件处理的地方,可以用CALayer+UIBersPath代替
2).减少不必要的frame、bounds、transform修改,在必要的时候一起修改。这就好比有10件物品,用车运一次就能够运完,就不要每次运一件物品运10次。
3).Autolayout会比直接设置frame消耗更多CPU资源
4).UIImageView的size最好跟图片的size相同,否则CPU还需要对图片进行处理
5).控制一下线程的最大并发量(虽然多线程带来了很大的优化,但是子线程并不是越多越好,这取决于CPU的最大处理数,超过这个值时,CPU过载,性能影响增大)
6).尽量把耗时的操作放到子线程(图片的解码、绘制(把图片放到上下文,然后再进行显示))

2、GPU

1).尽量避免段时间内展示大量图片,可以的话,把多张图片合成一张图片进行显示
2).GPU能处理的最大纹理尺寸是4096*4096,一旦超过这个尺寸,就会占用CPU资源进行处理,所以纹理尽量不要超过最大尺寸
3).尽量减少视图的数量和层次
4).减少透明的视图,不透明视图设置opaque为yes
5).尽量减少离屏渲染

四、离屏渲染

离屏渲染指的是在GPU在当前屏幕缓冲区以外再开辟一个缓冲区进行渲染操作,相比于当前屏幕渲染,离屏渲染的代价是很高的,主要体现在两个方面:

1.创建新的缓冲区

要想进行离屏渲染,首先要创建一个新的缓冲区,

2.上下文切换

离屏渲染的整个过程,需要多次切换上下文环境:先是从当前屏幕切换到离屏,等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上又需要将上下文环境切换到当前屏幕。而上下文环境的切换是需要消耗非常多的性能的。
下面的情况或者操作会引发离屏渲染:

  • 为图层设置遮罩(layer.mask)
  • 将图层的layer.masksToBounds/view.clipsToBouns属性设置为yes(这也是为什么需要将视图圆角处理尽量用layer代替的原因)
  • 将图层的layer.allowsGroupOpacity属性设置YES和layer的opacity小于1.0
  • 为图层设置阴影(layer.shadow)
  • 为图层设置layer.shouldRasterize = ture(光栅化:开启需要消耗额外的内存,但是开启后会减少layer的层级,并且会缓存图像,下次不需要重复绘制渲染)
  • 具有layer.cornerRadius,layer.edgeAnitialiasingMask,layer.allowsEdgeAnitialiasing(锯齿)的图层
  • 文本(任何种类,包括UILabel,CATextLayer,Core Text等)
  • 使用CGContext在drawRect:方法中绘制大部分情况下会导致离屏渲染,甚至仅仅是一个空的实现

五、离屏渲染的优化方案

iOS 9.0 之前UIImageView跟UIButton设置圆角都会触发离屏渲染,所以在项目中可以判断系统来觉得怎么实现UIImageView跟UIButton的圆角。iOS 9.0 之后UIButton设置圆角会触发离屏渲染,而UIImageView里的png图片设置圆角不会触发离屏渲染了,如果设置了其他阴影效果之类的还是会触发

1.圆角优化

用CAShapeLayer+UIBezierPath或者UIBezierPath+Core Graphics代替传统的圆角设置

2.shodow优化

对于shadow,如果图层是个简单的几何图形或者圆角图形,我们可以通过设置shadowPath来优化性能,能大幅提升高性能。示例如下:
imageView.layer.shadowColor=[UIColorgrayColor].CGColor;
imageView.layer.shadowOpacity=1.0;
imageView.layer.shadowRadius=2.0;
UIBezierPath *path=[UIBezierPathbezierPathWithRect:imageView.frame];
imageView.layer.shadowPath=path.CGPath;

3.利用XCode的Instruments工具检测

平时所说的卡顿主要是因为主线程执行了比较耗时的操作,可以添加Observer到主线程的Runloop中,通过监听RunLoop状态切换的耗时,以达到监控卡顿的目的。
主要耗时的来源有一下几点:
1)CPU处理,Processing
2)网络请求,Networking
3)定位,Location
4)图像,Graphics

解决方案:
  • 尽可能降低CPU、GPU消耗
  • 少用定时器
  • 优化I/O操作(1.尽量不要频繁写入小数据,最好批量一次性写入;2.读写大量重要数据时,考虑用dispatch_id,其提供了基于GCD的异步操作文件I/O的API。用dispatch_id,系统会优化磁盘访问;3.数据量比较大的,使用数据库(SQLite、CoreData等))
  • 网络优化(1.减少、压缩网络数据;2如果多次请求结果相同,尽量使用缓存;3.使用断点续传,否则网络不稳定时可能多次传输相同的内容;4.网络不可用时,不要尝试网络请求;5.让用户可以取消长时间运行或者速度很慢的网络操作,设置合理的超时时间;6.批量传输,比如,下载视频流时,不要传输很小的数据包,直接下载整个文件或者一大块一大块的下载。如果下载广告,一次性下载多一些,然后再慢慢显示。如果下载电子邮件,一次性下载多封,不要一封封下载)

本文知识点来源于网络,主要为博主学习日志记录用,如有侵权,请联系博主。

你可能感兴趣的:(iOS 卡顿原理及优化笔记)