app 性能优化的那些事(二)
来源:树下的老男孩
链接:http://www.jianshu.com/p/2a01e5e2141f
这次我们来说说iOS app中滑动的那些事。iOS为了提高滑动的流畅感,特意在滑动的时候将runloop模式切换到UITrackingRunLoopMode,在这个过程中专心做跟滑动相关的工作,这也就是在滑动过程中为什么nstimer无法工作的原因,因为两个没在同一mode下面。但我们可能经常会遇到滑动不怎么流畅的情况,比如在项目中碰到在滑动tableview的时候不怎么顺畅,感觉有点不爽,即便是在测试中表现最好的5s(touch之类的感受更直观)。
tableview 滑动不流畅
那碰到这种情况该怎么处理,分析图像动画性能主要用的是Core Animation这个组件,先简单介绍一下里面一些经常用到的选项:
Color Blended layers
标示混合的图层会为红色,不透明的图层为绿色,通常我们希望绿色的区域越多越好。
Color Hits Green and Misses Red
假如我们设置viewlayer的shouldRasterize为YES,那些成功被缓存的layer会标注为绿色,反之为红色,下面会有详细介绍。
Color copied images
标示那些被Core Animation拷贝的图片。这主要是因为该图片的色彩格式不能被GPU直接处理,需要在CPU这边做转换,假如在主线层做这个操作对性能会有一定的影响。
Color misaligned images
被缩放的图片会被标记为黄色,像素不对齐则会标注为紫色。
Color offscreen-rendered yellow
标示哪些layer需要做离屏渲染(offscreen-render)。
简单介绍完Core Animation的一些东西之后我们回过头来看看哪些问题会影响到图形的性能,下面这张图摘自WWDC2014(Advanced Graphics and Animations for iOS Apps,这上面的一些分享非常有技术性)
performance investigation mindset.png
当你碰到性能问题的时候,你可以思考一下:
是否受到CPU或者GPU的限制?
是否有不必要的CPU渲染?
是否有太多的离屏渲染操作?
是否有太多的图层混合操作?
是否有奇怪的图片格式或者尺寸?
是否涉及到昂贵的view或者效果?
view的层次结构是否合理?
那么哪些是你最该开始考虑的方向呢?通常发生图形性能问题的时候,比如列表滑动不顺畅、动画卡顿等,大部分都是由于Offscreen Rendering(离屏渲染)或者blending导致的,因为这在动画的每一帧都会涉及到。
offscreen-render
什么是offscreen-render?offscreen-render涉及的内容比较多,有offscreen-render那就有onscreen render,onscreen render指的是GPU在当前用于显示的屏幕缓冲区进行渲染,相反offscreen-render就是不在当前的屏幕缓存区,而在另外的缓冲区进行渲染,offscreen-render有两种形式:
CPU的offscreen-render
使用CPU来完成渲染操纵,通常在你使用:
drawRect (如果没有自定义绘制的任务就不要在子类中写一个空的drawRect方法,因为只要实现了该方法,就会为视图分配一个寄宿图,这个寄宿图的像素尺寸等于视图大小乘以 contentsScale的值,造成资源浪费)
使用Core Graphics
上面的两种情况使用的就是CPU离屏渲染,首先分配一块内存,然后进行渲染操作生成一份bitmap位图,整个渲染过程会在你的应用中同步的进行,接着再将位图打包发送到iOS里一个单独的进程–render server,理想情况下,render server将内容交给GPU直接显示到屏幕上。
GPU的offscreen-render
使用GPU在当前屏幕缓冲区以外开辟一个新的缓冲区进行绘制,通常发生的情况有:
设置cornerRadius, masks, shadows,edge antialiasing等
设置layer.shouldRasterize = YES
渲染流程
offscreen-render对性能到底有什么影响?通常大家说的离屏渲染指的是GPU这块(当然CPU这块也会有影响,也需要消耗一定的资源),比如修改了layer的阴影或者圆角,GPU需要做额外的渲染操作。通常GPU在做渲染的时候是很快的,但是涉及到offscreen-render的时候情况就可能有些不同,因为需要额外开辟一个新的缓冲区进行渲染,然后绘制到当前屏幕的过程需要做onscreen跟offscreen上下文之间的切换,这个过程的消耗会比较昂贵,涉及到OpenGL的pipeline跟barrier,而且offscreen-render在每一帧都会涉及到,因此处理不当肯定会对性能产生一定的影响,所以可以的话尽量减少offscreen-render的图层,查看哪些图层需要离屏渲染可以用Instruments的Core Animation工具进行检测,Color Offscreen-Rendered Yellow选项会将对应的图层标记为黄色。
Blending
假如最上层的view是不透明的,那直接使用这个view的对应颜色之就可以,但如果view是透明的,在计算像素的颜色值时就需要计算它下面图层,透明的视图越多,计算量就越大,因此也会对图形的性能产生一定的影响,所以可以的话也尽量减少透明图层的数目。
Demo
下面给出一个简单demo(https://github.com/FreeMind-LJ/OptimiseDemo)的优化过程,这个demo里面涉及到的问题是在实际项目中所碰到的,也就是最上面那张图里列表滑动不流畅情况—由阴影以及圆角导致的offscreen-render。
整个页面就是一个简单的tableview,其中头像为圆角,一个label有阴影效果,滑动的时候在iPod上帧率只有可怜的28FPS。
Color Offscreen-Rendered Yellow
28FPS.png
其中黄色的区域就是离屏渲染的地方,也就是含有圆角跟阴影的layer。
shadowPath
设置label的阴影效果可以通过:
cell.sign.layer.shadowOffset = CGSizeMake(0, 2);
cell.sign.layer.shadowOpacity = 0.5;
cell.sign.layer.shadowColor = [UIColor blackColor].CGColor;
但是你可以发现这会导致离屏渲染,一个简单的不需要离屏渲染的方法就是制定阴影的路径,也就是设置layer的shadowPath属性,通过instruments发现阴影的地方没有黄色了,帧率也提高到了40FPS:
cell.sign.layer.shadowPath = [UIBezierPath bezierPathWithRect:cell.sign.bounds].CGPath;
设置shadowPath消除离屏渲染.png
rasterize
对于圆角这种类似导致的性能问题,最简单的就是在列表中不要使用圆角,假如要使用圆角的话,一种最快提升性能的方式就是设置layer的shouldRasterize为YES:
cell.layer.shouldRasterize = YES;
cell.layer.rasterizationScale = [UIScreen mainScreen].scale;
虽然被Rasterize的图层也会引起离屏渲染,如下图所示,整个cell都被标示为黄色:
shouldRasterize.png
layer设置shouldRasterize=YES之后,会把被光栅化的图层保存成位图并缓存起来,其中圆角或者阴影之类的效果也是直接保存到位图当中,当需要渲染到屏幕上的时候只需要到缓存中去取对应的位图进行显示就行了,加快了整个渲染过程。可以通过勾选instruments core animation中的Color Hits Green and Misses Red选项来查看图层是否被缓存了,如果图层显示为绿色则表示已经被缓存起来了,也就是这个缓冲区的内容被复用了,不用在去重新创建缓冲区,反之则是用红色标示。如下图可以看到设置shouldRasterize之后,cell都被标示为绿色了,如果滑动过程中发现都是红色的证明就有问题了:
cached.png
再看看现在滑动的帧率:
优化后.png
可以发现现在滚动的性能大大提高了,光栅化对于那些有很多子view嵌套在一起、view的层级复杂或者有很复杂特效效果的图层有很明显的提升,因为这些内容都被缓存到位图当中了。但是使用光栅化需要注意一些内容:
适用于内容基本不变的图层
假如图层的内容经常变化,比如cell里面有涉及到动画之类的,那么缓存的内容就无效了,GPU需要重新创建缓存区,导致离屏渲染,这又涉及到OpenGL的上下文环境切换,反而降低性能。
不要过度使用
缓存区的大小被设置为屏幕大小的2.5倍,假如过分使用同样会导致大量的离屏渲染。
如果缓存的内容超过100ms没有被使用则会被回收。
tips
对于圆角可以使用一张中间圆形透明的图覆盖在上面,虽然这会引入blending操作,但是大部分情况下性能会比离屏渲染好。
让你的view层次结构平坦一些,因为OpenGL在渲染layer的时候,在碰到有子层级layer的时候可能需要停下来把两者合成到一个buffer里再接着渲染。(When the OpenGL renderer goes to draw each layer, it may have to stop for some subhierarchies and composite them into a single buffer).
延迟加载图片
有时候在边滚动边设置图片的时候可能会有一定的影响,因此可以在滚动的时候imageview不执行setimage的操作,滚动停止的时候才加载图片,由于滚动的时候NSRunloop是处于UITrackingRunLoopMode模式下,可以采用如下的方式,将设置图片放到NSDefaultRunLoopMode模式下才进行:
UIImage *downloadedImage = ...;
[self.avatarImageView performSelector:@selector(setImage:)
withObject:downloadedImage
afterDelay:0
inModes:@[NSDefaultRunLoopMode]];
图片加载的极限优化方式:FastImageCache
https://github.com/path/FastImageCache
图形性能这块有什么好的想法也可提出来交流一下~~
参考:
https://lobste.rs/s/ckm4uw/a_performance-minded_take_on_ios_design/comments/itdkfh
Advanced Graphics and Animations for iOS Apps
http://iosinjordan.tumblr.com/post/56778173518/help-my-tables-dont-scroll-smoothly
转载于:https://www.cnblogs.com/fengmin/p/5937316.html
app 性能优化的那些事(二)相关推荐
- iOS app性能优化的那些事
iPhone上面的应用一直都是以流畅的操作体验而著称,但是由于之前开发人员把注意力更多的放在开发功能上面,比较少去考虑性能的问题,可能这其中涉及到objective-c,c++跟lua,优化起来相对 ...
- Android APP性能优化
转载自:https://www.cnblogs.com/qwangxiao/p/8727229.html Android APP性能优化(最新总结) 导语 安卓大军浩浩荡荡,发展已近十个年头,技术优化 ...
- Android APP性能优化(一)
Android APP性能优化(最新总结) 安卓大军浩浩荡荡,发展已近十个年头,技术优化日异月新,如今Android 8.0 Oreo 都发布了,Android系统性能已经非常流畅了.但是,到了各大厂 ...
- App性能优化(布局优化,线程优化,app瘦身优化,页面切换优化,App启动优化,内存优化)
Android APP性能优化(最新总结) 在目前Android开发中,UI布局可以说是每个App使用频率很高的,随着UI越来越多,布局的重复性.复杂度也随之增长,这样使得UI布局的优化,显得至关重要 ...
- WP7 App性能优化(8):检测应用程序性能(Ⅰ)
有很多方法监视应用程序的性能并检测性能问题.检测内存占用是其中之一.也可以启用重绘区域着色和视图缓存,从而可视化的监视相关资源的使用情况.也可以打开帧频计数器使其在Windows Phone 7模拟器 ...
- 【安卓开发系列 -- APP 】APP 性能优化 -- 崩溃分析
[安卓开发系列 -- APP ]APP 性能优化 -- 崩溃分析 [1]Native Crash 分析示例 [1.1]Linux 编译 breadpad 下载 breadpad 源码 git clon ...
- Android App 性能优化系列结语篇
Android App 性能优化系列结语篇 原文出处:http://gold.xitu.io/post/581f4ad667f3560058a33057 关于Android App的优化, 从第一篇的 ...
- Android App性能优化系列
Android App性能优化系列 关于Android App的优化,从第一篇的计划开始,到内存优化的系列文结束,不知不觉近三个月的时间,写了十五六篇相关的博文,算是对自己的知识的一个系统化,也希望能 ...
- Android App 性能优化总结
Android App 性能优化系列结语篇 转发自:http://blog.lmj.wiki/2016/11/06/app-opti/app_opt_summary/#more 关于Android A ...
最新文章
- 2018区块链生存指南:要做飞行的猪、摔不坏的弹球、未来的种子
- python中lt方法_Python的富比较方法__lt__、__gt__之间的关联关系分析
- 数据中心智慧机房解决方案
- 我们常常意识不到问题的存在,直到有人解决了这些问题
- Python字符串前加u/r/b的作用
- 十一、Grafana监控系统
- opencv支持python3吗_Python3.4+opencv3
- 一道内存分配的面试题后续
- 博主已开启评论精选什么意思_小白必看!想要成为小红书博主,首先要掌握4个工具!...
- nginx启动重启停止
- Intel Core Enhanced Core架构/微架构/流水线 (7) - 栈指针跟踪器/微熔合
- android 绘制按钮,Android:使用xml定义创建一个三角形的按钮(可绘制)
- 致00后大学新生:从今天起,为转离这些专业而努力
- python gui下载进度条_对python GUI实现完美进度条的示例详解
- 基于SSM的废品商城
- vs2017如何编写python_vs2017添加python的方法
- word课程表设置符号与编号_小学生课程表word模板 小学生使用WORD.doc
- 安装python失败的方法_安装python不失败的方法
- Word中插入Endnote设置指定期刊参考文献样式(逐步操作讲解插入期刊和网页文献)
- word另存为PDF时Mathtype公式显示不全的问题
热门文章
- ubuntu mysql 多端口_ubuntu 16.04下mysql5.7.17开放远程3306端口
- 【收藏】运维必备的问题定位工具及案例分析
- 再见 2020!Apache RocketMQ 发布 4.8.0,DLedger 模式全面提升!
- 开放应用模型操作指南(一)| 云服务一键接入 OAM 体系
- K8s 学习者绝对不能错过的最全知识图谱(内含 58个知识点链接)
- python import requests报错_import requests 出错,搜了很多,没解决,求教.
- 多节锂电串联保护板ic_BMS电池管理系统与锂电池保护板的区别
- 计算机专业复试线380,445名400+的科软复试线388分,计算机学硕380分,卷炸了
- mysql 查询if语句执行顺序_MySQL 语句的执行顺序
- rk android8.1加密,Android 8.1RK平台增加自定义脚本,修改文件权限