性能优化总结

界面显示原理:

                                                      

                  CRT显示器和液晶显示器显示原理都是一样的:CRT电子枪按照上面的方式,从上到下一行行扫描,每次换行扫描显示器会发出一个水平同步信号,简称HSync; 但从上往下扫描完之后,就相当于是一帧画面绘制完成,电子枪回复到原位,准备绘制下一帧画面之前,显示器会发出一个垂直同步信号,简称VSync;   显示器通常以固定频率进行刷新,这个刷新率就是VSync信号产生的频率。

 

 

卡顿产生的原因:        

  

                在VSync信号到来后,系统图形服务会通知APP,APP主线程开始在CPU中计算显示内容,比如视图的创建、布局计算、图片解码、文本绘制等。 随后CPU会将计算好的内容提交到GPU去,由GPU进行变换、合成、渲染。随后GPU会把渲染结果提交到帧缓冲区,等待下一次VSync信号到来时显示到屏幕上。 如果在一个VSync时间捏,CPU或者GPU没有完成内容提交,则那一帧就会被丢弃,等待下一次机会再显示,而这时显示屏会保留之前的内容不变,这就是界面卡顿的原因。

           所以不管是CPU还是GPU不论哪个阻碍了显示流程,都会造成掉帧现象;

解决方案:

  CPU:

         对象创建:使用视图懒加载的方式避免过多创建对象;  不涉及到UI操作使用CALayer(但是包含CALayer的控件都在只能在主线程上创建和操作)

         对象调整:尽量避免调整视图层级、添加和移除视图,因为会涉及到UIView、CALayer 之间会出现很多方法调用与通知; (CALayer内部并没有属性,当调用属性方法时内部会在运行时resolveInstanceMethod为对象临时添加一个方法,并把值保存在内部的Dictionary里)

         布局计算:在获取到网络数据之后,在子线程中使用frame手动计算布局,在view的layoutsubview方法里一次给控件的frame赋值。

         文本计算:feed流的列表推荐在子线程中使用[NSAttributedString boundingRectWithSize:options:context:]来计算文本宽高

        图片解码:当你用 UIImage 或 CGImageSource 的那几个方法创建图片时,图片数据并不会立刻解码。图片设置到 UIImageView 或者 CALayer.contents 中去,并且 CALayer 被提交到 GPU 前,CGImage 中的数据才会得到解码。这一步是发生在主线程的,并且不可避免。如果想要绕开这个机制,常见的做法是在后台线程先把图片绘制到 CGBitmapContext 中,然后从 Bitmap 直接创建图片。目前常见的网络图片库都自带这个功能。 (使用SDWebImage)

         图像绘制:图像的绘制通常是指用那些以 CG 开头的方法把图像绘制到画布中,然后从画布创建图片并显示这样一个过程。这个最常见的地方就是 [UIView drawRect:] 里面了。  这里通常的优化做法是放到异步线程里进行异步绘制。

 

GPU:

         视图混合:当多个视图(或者说 CALayer)重叠在一起显示时,GPU 会首先把他们混合到一起。如果视图结构过于复杂,混合的过程也会消耗很多 GPU 资源。为了减轻这种情况的 GPU 消耗,应用应当尽量减少视图数量和层次,并在不透明的视图里标明 opaque 属性以避免无用的 Alpha 通道合成。

         离屏渲染:那就尽量减少离屏渲染,使用shadowPath来设置阴影,使用剪裁过的图片来代替圆角,而不是   直接使用CornerRadius,图层蒙版能不用尽量不用。  (通常光栅化、遮罩、阴影、抗锯齿、圆角、渐变等都会引起离屏渲染)

       

谈谈离屏渲染:

            屏幕中的渲染有三种:

                   GPU中的屏幕渲染:

                                1、On-Screen Rendering (当前屏幕渲染)

                                     意为当前屏幕渲染,指的是GPU的渲染操作是在当前用于显示的屏幕缓冲区中进行

                                2、Off-Screen Rendering  (离屏渲染)

                                     意为离屏渲染,指的是GPU在当前屏幕缓冲区以外新开辟一个缓冲区进行渲染操作

                    CPU中的离屏渲染:  (特殊离屏渲染,即不在GPU中的渲染)

                                  如果我们重写drawRect方法,并且使用任何Core Graphics的技术进行了绘制操作,就涉及到了CPU渲染;

                                  Core Graphics里的方法通常都是线程安全的,所以可以开辟异步线程进行异步绘制,显示的时候再放回主线程;

              离屏渲染为什么会消耗性能? 

                      答:离屏渲染的整个过程,需要多次切换上下文环境; 先是在当前屏幕切换到离屏,等到离屏渲染结束以后,将离屏缓冲区的渲染结果显示到屏幕上,又需要将上下文环境切换到当前屏幕。  而上下文环境的切换要付出很大代价,非常消耗性能。

               既然离屏渲染这么消耗性能,为什么有这套机制呢?

                       答:有些效果被认为不能直接呈现于屏幕,而需要在别的地方做额外的处理预合成。图层属性的混合体没有预合成之前不能直接在屏幕中绘制,所以就需要屏幕外渲染。屏幕外渲染并不意味着软件绘制,但是它意味着图层必须在被显示之前在一个屏幕外上下文中被渲染(不论CPU还是GPU)。  比如光栅化、遮罩、阴影、抗锯齿、圆角、渐变等都会引起离屏渲染;

 

 

检测滑动性能的工具和检测离屏渲染的工具:

           1、用 Instuments 的 GPU Driver 预设,能够实时查看到 CPU 和 GPU 的资源消耗;

           2、Xcode->Open Develeper Tools->Instruments->Core Animation

          3、CADisplayLink

 

参考链接:

             https://blog.ibireme.com/2015/11/12/smooth_user_interfaces_for_ios/

             https://www.jianshu.com/p/39b91ecaaac8

             https://www.jianshu.com/p/59980004ac95

             https://www.jianshu.com/p/cff0d1b3c915

             https://www.cnblogs.com/fishbay/p/7576176.html

             https://www.jianshu.com/p/4008ec3cacaa

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值