http://www.cocoachina.com/ios/20160920/17602.html
;
我猜测,解压缩操作中,每一个像素点都会分配一个空间来存储相关值,那么分辨率越高的图片,就意味着更多数量的像素点,也就意味着需要分配更多的空间!所以对于高分辨率图来说,解压缩操作的确会造成内存飙升,即使是几M的图片,解压缩过程中也是有可能消耗上G的内存!
既然如此,我决定按照harishkashyap大神的方法,直接让下载高分辨率图的地方,禁止解压缩操作!
朋友说,高清图涉及到的地方,都全部已经封装起来了,那么就轻松了很多。为了保证封装类不对外界产生影响,我只在调用封装类时,禁用解压缩,调用完毕再恢复原设置即可。这样既能保证高分辨率图不crash,也能保证其他地方,普通图片依旧可以通过解压缩进行优化。
朋友封装的是一个控制器,所以我决定在控制器loadView方法中禁用解压缩,在delloc方法中恢复原设置:
1、首先在封装的控制器中定义变量用于存储原设置:
static BOOL SDImageCacheOldShouldDecompressImages = YES;static BOOL SDImagedownloderOldShouldDecompressImages = YES;
2、loadView中保存原设置并且禁用解压缩:
SDImageCache *canche = [SDImageCache sharedImageCache];
SDImageCacheOldShouldDecompressImages = canche.shouldDecompressImages;
canche.shouldDecompressImages = NO;
SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];
SDImagedownloderOldShouldDecompressImages = downloder.shouldDecompressImages;
downloder.shouldDecompressImages = NO;
3、dell中恢复原设置:
-(void)dealloc {
SDImageCache *canche = [SDImageCache sharedImageCache];
canche.shouldDecompressImages = SDImageCacheOldShouldDecompressImages;
SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];
downloder.shouldDecompressImages = SDImagedownloderOldShouldDecompressImages;
}
资讯
论坛
代码
工具
招聘
CVP
外快
博客new
登录|注册
iOS开发
Swift
App Store研究
产品设计
应用
VR
游戏开发
苹果相关
安卓相关
营销推广
业界动态
程序人生
首页>iOS开发
使用SDWebImage和YYImage下载高分辨率图,导致内存暴增的解决办法
2016-09-20 11:19编辑:不灭的小灯灯分类:iOS开发来源:ocarol的
164759
iOS
招聘信息:
UI设计
Mac开发
Unity3D手游客户端主程
技术合伙人
移动应用开发项目经理
iOS Developer
微信书城开发
数字图书商城开发
iOS维护
手机视频剪辑字幕配音工具iOS类app
点读笔开发
最近,收到朋友求助,说是有个控制器,一进去就crash,而且手机非常的烫,用instrument跑了跑,发现内存暴增几百兆;如图:
图中可以看出,内存暴增的罪魁祸首是YYImage,再进一步定位问题,如图:
现在已经可以很清楚的知道,具体是哪些代码导致内存飙升的,这个方法“YYCGImageCreateDecodeCopy”,主要是对图像进行解压缩操作;同样的,换成SDWebImage,也出现了相同情况,由于某些原因,之后的分析都将以SDWebImage为例。
先贴上朋友调用的SDWebImage的代码:
[self sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"defaulImage"] options:SDWebImageProgressiveDownload completed:nil];
instrument分析图:
代码定位:
同样的,也是在解压缩的时候,出现内存飙升,但是为什么会这样呢?
首先我想到“Create”必须得对应一个“Release”,于是我认真的看了每一行代码,无论是YYImage还是SDWebImage,都严格遵守了这一准则,既然都有Release,那么就不是内存泄露了,应该是在这几行代码执行的过程中,产生的内存消耗。可是怎么会消耗这么大呢?一张图片也就几M的大小啊,这个解压缩存在的意义是什么呢?
我从“H_伟华 博乐家园”的一篇博客中找到了解压缩存在的意义(http://blog.163.com/huang1988519@126/blog/static/737875752013101803137445/)
当完成图片加载或者从本地加载图片时,还会有轻微的卡顿。
因为当显示或者绘制的时候,UIKit 只做了额外的延迟初始化和消耗很高解码。
而下面的代码片段,从后台线程解压缩成合适的格式,从而让系统不必做额外的转换。
然后在主线程上显示
我又疑惑了,既然是为了优化,为啥会适得其反呢?我百思不得其解,最后在SDWebImage的issues找到了相关的讨论:
https://github.com/rs/SDWebImage/issues/538
其中一个harishkashyap大神是这么回答的:
harishkashyap commented on Dec 23, 2014
Its the memory issue again. decodedImageWithImage takes up huge memory and causes the app to crash. I have added an option to put this off in the library but defaulting to YES so there aren't any breaking changes. If you put off the decodeImageWithImage method in both image cache and image downloader then you shouldn't be seeing the VM: CG Raster data on the top consuming lots of memory
decodeImageWithImage is supposed
to decompress images and cache them so the loading on
tableviews/collectionviews become better. However, with large set of
images being loaded, the experience worsened and the memory of
uncompressed images even with thumbnails can consume GBs of memory.
Putting this off only improved performance.
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
https://github.com/harishkashyap/SDWebImage/tree/fix-memory-issues
这位大神提到,decodeImageWithImage这个方法用于对图片进行解压缩并且缓存起来,以保证tableviews/collectionviews
交互更加流畅,但是如果是加载高分辨率图片的话,会适得其反,有可能造成上G的内存消耗。该大神建议,对于高分辨率的图片,应该禁止解压缩操作,相关的代码处理为:
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
虽然这位大神给了肯定的答案,但是为什么会如此呢?
我查阅了apple官方文档对CGBitmapContextCreate函数的注解:
图中红框部分的参数,引起了我的注意:
bitsPerComponent 表示存入内存中的每个像素中的每一个组件所占的位数;
bytesPerRow 表示存入内存中的位图的每一行所占的字节数;
我猜测,解压缩操作中,每一个像素点都会分配一个空间来存储相关值,那么分辨率越高的图片,就意味着更多数量的像素点,也就意味着需要分配更多的空间!所以对于高分辨率图来说,解压缩操作的确会造成内存飙升,即使是几M的图片,解压缩过程中也是有可能消耗上G的内存!
既然如此,我决定按照harishkashyap大神的方法,直接让下载高分辨率图的地方,禁止解压缩操作!
朋友说,高清图涉及到的地方,都全部已经封装起来了,那么就轻松了很多。为了保证封装类不对外界产生影响,我只在调用封装类时,禁用解压缩,调用完毕再恢复原设置即可。这样既能保证高分辨率图不crash,也能保证其他地方,普通图片依旧可以通过解压缩进行优化。
朋友封装的是一个控制器,所以我决定在控制器loadView方法中禁用解压缩,在delloc方法中恢复原设置:
1、首先在封装的控制器中定义变量用于存储原设置:
static BOOL SDImageCacheOldShouldDecompressImages = YES;static BOOL SDImagedownloderOldShouldDecompressImages = YES;
2、loadView中保存原设置并且禁用解压缩:
SDImageCache *canche = [SDImageCache sharedImageCache];
SDImageCacheOldShouldDecompressImages = canche.shouldDecompressImages;
canche.shouldDecompressImages = NO;
SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];
SDImagedownloderOldShouldDecompressImages = downloder.shouldDecompressImages;
downloder.shouldDecompressImages = NO;
3、dell中恢复原设置:
-(void)dealloc {
SDImageCache *canche = [SDImageCache sharedImageCache];
canche.shouldDecompressImages = SDImageCacheOldShouldDecompressImages;
SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];
downloder.shouldDecompressImages = SDImagedownloderOldShouldDecompressImages;
}
再次用instrument跑了一下,方法果然有效,内存彻底降下来了,如图:
当然,你也可以设置SDWebImage的其他参数,比如是否缓存到内存以及内存缓存最高限制等,来保证内存安全:
shouldCacheImagesInMemory 是否缓存到内存
maxMemoryCost 内存缓存最高限制
号外:苹果官方给出了一个下载高清大图的demo,内存消耗很低。感兴趣的朋友也可以看看:
https://developer.apple.com/library/ios/samplecode/LargeImageDownsizing/Introduction/Intro.html
文章转自ocarol的
微信扫一扫
订阅每日移动开发及APP推广热点资讯
公众号:CocoaChina
我要投稿收藏文章
分享到:
15
上一篇:兼容iOS 10 资料整理笔记
下一篇:利用Mob实现免费短信验证码
相关资讯
iOS代码设计中的开放与封闭
iOS动画详解(学习动画看这一篇就够了)
3分钟实现iOS语言本地化/国际化(图文详解)
iOS Crash 杀手排名
iOS之两圆之间标准圆的随机生成
iOS百度地图路径规划和POI检索详细总结
iOS架构设计解耦的尝试之模块间通信
一步步构建iOS路由
iOS A/B Test 方案探索
iOS即时通讯,从入门到“放弃”?
我来说两句
发表评论
您还没有登录!请登录或注册
所有评论(16)
吃鱼的梵高2016-09-28 09:55:14
不错,实用,有深度,好文!
00回复
zf55662652016-09-27 16:34:09
不错不错,以前只知道问题所在,不知道如何处理,学习了!
00回复
蜗牛的苦修2016-09-23 11:36:32
mark
00回复
vansouth2016-09-21 15:42:18
之前遇到类似问题,终于有大哥归纳出来了 棒棒棒
00回复
假面欢颜2016-09-21 11:24:20
看了这篇文章终于知道以前有个项目加载大图闪退的原因了
00回复
于少波2016-09-21 10:17:41
如果界面是tabbar的控制器, 不走dealloc方法, 恢复原设置放在viewWillDisAppear里可以吗
00回复
于少波2016-09-21 10:21:31
回复:于少波刚才我试了楼主的办法, 直接黑屏了 页面上什么都没有加载出来
00回复
艾姆希2016-09-22 12:00:09
回复:于少波viewWillDisAppear里会黑屏?
00回复
copy_x2016-09-20 17:18:49
如果是多线程怎么办?这里展示高清大图的时候,前面的画面还在下载并显示其他图片的话,感觉会受到影响的吧
00回复
EdwardYongaYao2016-09-20 16:53:27
6666mark了
00回复
_gufs2016-09-20 16:42:13
这篇文章前几天看过了 真的很好,解决我的大问题,不过在4/4s上还是崩溃
00回复
linlinyao12016-09-20 15:01:57
图片本来就不应该太高清,最大适配到plus的分辨率就行了,多了也是浪费
00回复
_gufs2016-09-20 16:40:45
回复:linlinyao1如果有放大功能呢~~~
00回复
linlinyao12016-09-20 15:01:57
图片本来就不应该太高清,最大适配到plus的分辨率就行了,多了也是浪费
00回复
idbuchun2016-09-21 11:07:54
回复:linlinyao1plus分辨率 *2 ,哈哈
00回复
frew2016-09-20 14:05:33
之前碰到过美工突然把一个产品的图片,没有处理,直接传上去了,导致滑动到那个图片,APP就崩了,当时只知道是图片问题,没有深入研究,作者谢了。
00回复
热门资讯
一步步构建iOS路由
点击量7753
微信小程序出师不利,谷歌百度或推新Web应用标准抄后路
点击量6194
六年程序生涯
点击量4495
苹果Swift语言之父出走 跳槽特斯拉任软件副总
点击量3640
苹果怀旧了?iPhone 8或将回归玻璃机身
点击量3605
源码推荐:微信小程序开源项目库汇总 列表和网格视图的相互切换
点击量3281
苹果App Store排名遭大面积刷榜?淘宝商家曝光内幕
点击量2860
关于上传照片交互逻辑的思考
点击量2787
程序员该用哪种姿势来理财
点击量2720
二十个令程序员泪流满面的瞬间……
点击量2616
综合评论
好文
Long龙评论了3分钟实现iOS语言本地化/国际化(图文详解)...
挺实用的
Cocoa20KCJ评论了iOS Crash 杀手排名
写的非常好
wsw_ios评论了细聊 Cocoapods 与 Xcode 工程配置...
iOS8之后可以用动态framework, 只是framework必须要打包时候一起签名, 不然dlopen验证不通过不能打开该动态库. 虽然不能实现服务端动态更新framework, 但也可以实现app运行时按需加载模块代码(动态framework)
captain_black评论了Objective-C库文件使用小记...
不能立即生效,需要重新启动!!!如何破?重新加载window 的 rootViewController 那太突然或者不太合理(在进入几层界面中切换时)
tikeyc评论了3分钟实现iOS语言本地化/国际化(图文详解)...
mark
ganxie.wang评论了iOS10里的通知与推送...
也不能一概而论,有时上班的时候各种打扰,各种提问,下班了终于可以安心写代码了....
倔。犟评论了不要相信程序员在加班时间写的代码...
厉害 厉害
ohMyKing评论了细聊 Cocoapods 与 Xcode 工程配置...
今年上班第一天,看的第一篇文字,确实不错,祝大家工作顺利,升职加薪
tikeyc评论了3分钟实现iOS语言本地化/国际化(图文详解)...
你到底有没有用苹果手机啊,系统现在有 Night Shift功能,就如同你所说的只能体验,而且效果更好.所以现在夜间功能根本没必要,省了多少事
281090013评论了为什么很多主流App没有『夜间模式』?...
相关帖子
是不是注册vungle必须是公司呢?
app如果多语言支持的是中文和英文
上海坑爹面试互联网公司排行,你是否中枪
同个工程多个target后jump to definition的问题
2万元求大神分析球球大作战登陆协议
完Aspen.HYSYS.v8.2 HYSUPSTRM lic好用模块
新年第一贴
进入了迷茫的阶段,不知道下一步该如何走!
请问GPUImage如何使用组合滤镜呢?
sinaweixinmail回到顶部
关于我们商务合作联系我们合作伙伴
北京触控科技有限公司版权所有
©2016 Chukong Technologies,Inc.京ICP备 11006519号 京ICP证 100954号京公网安备11010502020289京网文[2012]0426-138号