⾯试题:iOS性能优化——图⽚加载和处理
图⽚的显⽰分为三步:加载、解码、渲染。
通常,我们操作的只有加载,解码和渲染是由UIKit进⾏。
[图⽚上传失败...(image-c58720-1620971417989)]
元旦小短句什么是解码?
以UIImageView为例。当其显⽰在屏幕上时,需要UIImage作为数据源。
UIImage持有的数据是未解码的压缩数据,能节省较多的内存和加快存储。
当UIImage被赋值给UIImage时(例如imageView.image = image;),图像数据会被解码,变成RGB的颜⾊数据。
解码是⼀个计算量较⼤的任务,且需要CPU来执⾏;并且解码出来的图⽚体积与图⽚的宽⾼有关系,⽽与图⽚原来的体积⽆关。
其体积⼤⼩可简单描述为:宽 * ⾼ * 每个像素点的⼤⼩ = width * height * 4bytes。
[图⽚上传失败...(image-bd559f-1620971417989)]
图像解码操作会造成什么问题?
以我们常见的UITableView和UICollectionView为例,假如我们在使⽤⼀个多图⽚显⽰的功能:
[图⽚上传失败...(image-a5ed7c-1620971417989)]
天津封城最新消息2022在上下滑动显⽰图⽚的过程中,我们会在cellFor的⽅法加载UIImage图⽚、赋值给UIImageView,相当于在主线程同时进⾏IO操作、解码操作等,会造成内存迅速增长和CPU负载瞬间提升。
并且内存的迅速增加会触发系统的内存回收机制,尝试回收其他后台进程的内存,增加CPU的⼯作量。如果系统⽆法提供⾜够的内存,则会先结束其他后台进程,最终⽆法满⾜的话会结束当前进程。
[图⽚上传失败...(image-c54dd9-1620971417989)]
那么如何对这种情况进⾏优化 ?
手机内存卡无法格式化优化1:降采样
在滑动显⽰的过程中,图⽚显⽰的宽⾼远⽐真实图⽚要⼩,我们可以采⽤加载缩略图的⽅式减少图⽚
的占⽤内存。
如下图所⽰:
[图⽚上传失败...(image-8c0450-1620971417989)]
我们加载jpeg的图⽚,然后进⾏相关设置,解码后根据设置⽣成CGImage缩略图,最后包装成UIImage,最终传递给UIImageView渲染。
思考:这⾥的解码步骤为何不是上⽂提到的imageView.image=image时机?
那么WWDC所讲的内容我们可以认为是事实上的结果。
于是可以使⽤我们所掌握的基础知识,还有对iOS系统的了解来分析WWDC上⾯所提到的现象,看我们的iOS知识体系是否存在缺陷;另
外,WWDC介绍的很多知识点同样免验证的加⼊⾃⼰的知识体系。
电脑屏幕抖动这就是我⽐较喜欢的⼀种看WWDC视频的学习⽅式。
以上⽂提到的线程爆炸为例,看看这种⽅式的好处。
原⽂如下:
Thread Explosion(线程爆炸)
More images to decode than available CPUs(解码图像数量⼤于CPU数量)
GCD continues creating threads as new work is enqueued(GCD创建新线程处理新的任务)
Each thread gets less time to actually decode images(每个线程获得很少的时间解码图像)
从这个案例我们学习到如何避免图像解码的线程爆炸,但还能扩散思维:
我们分析苹果⼯程师的逻辑:
原因(解码任务过多)==> 过程(GCD开启更多线程) ==> 结果( 每个线程获得更少的时间)
延伸出来的问题有:
GCD是如何处理异步队列?为何会启动多个线程处理?
多少的线程数量是合适的?线程的cpu时间分配和切换代价如何?
...
举⼀反三,类似的问题太多。但是这样的思考稍显混乱,仍有优化的空间。
把脑海关于GCD的认知提炼出来:
1、GCD是⽤来处理⼀系列任务的同步和异步执⾏,队列有串⾏和并发两种,与线程的关系只有主线程和⾮主线程的区别;
2、串⾏队列是执⾏完当前的任务,才会执⾏下⼀个block任务;并⾏队列是多个block任务并⾏执⾏,GCD会根据任务的执⾏情况分配线程,原则是尽快完成所有任务;
接下来的表现是操作系统相关的知识:
1、iOS系统中进程和线程的关联,每个启动的APP都是⼀个进程,其中有多个线程;
2、cpu的时间是分为多个时间⽚,每个线程轮询执⾏;
3、线程切换执⾏有代价,但⽐进程切换⼩得多;
4、每个cpu核⼼在同⼀时刻只能执⾏⼀个线程;
⾄此我们可以结合操作系统和GCD的知识,猜测底层GCD的实现思路和线程爆炸情况下的表现:
主线程把多个任务block放到并发队列,GCD先启动⼀个线程处理解码任务,线程执⾏过程中遇到耗时操作时(IO等待、⼤量CPU计算),短时折纸盒子
市场营销课程间内⽆法完成,为了不阻塞后续任务的执⾏,GCD启动新的线程处理新的任务。
集合此案例,我们能回答相关问题:
1、现在有⼀个很复杂的计算任务,例如是统计⼀个5000x5000图⽚中像素点的RGB颜⾊通道,如果⽤分为25个任务放到GCD并发队列,把⼤图切分成25个1000x1000⼩图分别统计,是否会速度的提升?
2、GCD的串⾏队列和并发队列的应⽤场景有何不同?
以上⼀些平时学习的感受。
如果能对你有所触动,⼗分荣幸;
如果你觉得能改进,欢迎提出来帮助我成长;
如果你觉得毫⽆⽤处,⾄少你知道⼀种错误的学习⽅法。
版权声明:本站内容均来自互联网,仅供演示用,请勿用于商业和其他非法用途。如果侵犯了您的权益请与我们联系QQ:729038198,我们将在24小时内删除。
发表评论