iOS-使用SDWebImage和YYImage下載高分辨率圖撇贺,導(dǎo)致內(nèi)存暴增的解決辦法

原文鏈接:http://www.reibang.com/p/1c9de8dea3ea


最近巡莹,遇到一個(gè)問題司志,有個(gè)控制器,一進(jìn)去就crash,而且手機(jī)非常的燙降宅,用instrument跑了跑骂远,發(fā)現(xiàn)內(nèi)存暴增幾百兆;如圖:

Snip20160725_3.png

  圖中可以看出腰根,內(nèi)存暴增的罪魁禍?zhǔn)资荵YImage激才,再進(jìn)一步定位問題,如圖:

Snip20160725_6.png

現(xiàn)在已經(jīng)可以很清楚的知道,具體是哪些代碼導(dǎo)致內(nèi)存飆升的瘸恼,這個(gè)方法“YYCGImageCreateDecodeCopy”劣挫,主要是對圖像進(jìn)行解壓縮操作;同樣的东帅,換成SDWebImage压固,也出現(xiàn)了相同情況,由于某些原因靠闭,之后的分析都將以SDWebImage為例帐我。

先貼上調(diào)用的SDWebImage的代碼:

[selfsd_setImageWithURL:[NSURLURLWithString:imageUrl] placeholderImage:[UIImageimageNamed:@"defaulImage"] options:SDWebImageProgressiveDownload completed:nil];

instrument分析圖:

Snip20160725_4.png

代碼定位:

Snip20160725_8.png

同樣的,也是在解壓縮的時(shí)候阎毅,出現(xiàn)內(nèi)存飆升焚刚,但是為什么會這樣呢?

首先我想到“Create”必須得對應(yīng)一個(gè)“Release”扇调,于是我認(rèn)真的看了每一行代碼矿咕,無論是YYImage還是SDWebImage,都嚴(yán)格遵守了這一準(zhǔn)則狼钮,既然都有Release碳柱,那么就不是內(nèi)存泄露了,應(yīng)該是在這幾行代碼執(zhí)行的過程中,產(chǎn)生的內(nèi)存消耗〈樽ィ可是怎么會消耗這么大呢糠雨?一張圖片也就幾M的大小啊,這個(gè)解壓縮存在的意義是什么呢标沪?

我從“H_偉華 博樂家園”的一篇博客中找到了解壓縮存在的意義(http://blog.163.com/huang1988519@126/blog/static/737875752013101803137445/)

當(dāng)完成圖片加載或者從本地加載圖片時(shí),還會有輕微的卡頓。因?yàn)楫?dāng)顯示或者繪制的時(shí)候半火,UIKit只做了額外的延遲初始化和消耗很高解碼。而下面的代碼片段季俩,從后臺線程解壓縮成合適的格式钮糖,從而讓系統(tǒng)不必做額外的轉(zhuǎn)換。然后在主線程上顯示

我又疑惑了酌住,既然是為了優(yōu)化店归,為啥會適得其反呢?我百思不得其解酪我,最后在SDWebImage的issues找到了相關(guān)的討論:

https://github.com/rs/SDWebImage/issues/538

其中一個(gè)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這個(gè)方法用于對圖片進(jìn)行解壓縮并且緩存起來,以保證tableviews/collectionviews 交互更加流暢都哭,但是如果是加載高分辨率圖片的話肄满,會適得其反谴古,有可能造成上G的內(nèi)存消耗。該大神建議稠歉,對于高分辨率的圖片掰担,應(yīng)該在圖片解壓縮后,禁止緩存解壓縮后的數(shù)據(jù)怒炸,相關(guān)的代碼處理為:

[[SDImageCache sharedImageCache]setShouldDecompressImages:NO];[[SDWebImageDownloader sharedDownloader]setShouldDecompressImages:NO];

雖然這位大神給了肯定的答案带饱,但是為什么會如此呢?

我查閱了apple官方文檔對CGBitmapContextCreate函數(shù)的注解:

Snip20160725_10.png

圖中紅框部分的參數(shù)阅羹,引起了我的注意:

bitsPerComponent 表示存入內(nèi)存中的每個(gè)像素中的每一個(gè)組件所占的位數(shù)勺疼;

bytesPerRow 表示存入內(nèi)存中的位圖的每一行所占的字節(jié)數(shù);

我猜測捏鱼,解壓縮操作中执庐,每一個(gè)像素點(diǎn)都會分配一個(gè)空間來存儲相關(guān)值,那么分辨率越高的圖片导梆,就意味著更多數(shù)量的像素點(diǎn)轨淌,也就意味著需要分配更多的空間!所以對于高分辨率圖來說看尼,如果緩存解壓縮之后的數(shù)據(jù)递鹉,即使是幾M的圖片,也是有可能消耗上G的內(nèi)存藏斩!

既然如此躏结,我決定按照harishkashyap大神的方法,直接讓下載高分辨率圖的地方狰域,避免緩存解壓縮后的數(shù)據(jù)操作媳拴!

項(xiàng)目中,高清圖涉及到的地方兆览,都全部已經(jīng)封裝起來了屈溉,那么就輕松了很多。為了保證封裝類不對外界產(chǎn)生影響拓颓,我只在調(diào)用封裝類時(shí)语婴,禁用緩存解壓縮數(shù)據(jù)描孟,調(diào)用完畢再恢復(fù)原設(shè)置即可驶睦。這樣既能保證高分辨率圖不crash,也能保證其他地方匿醒,普通圖片依舊可以通過緩存解壓縮數(shù)據(jù)進(jìn)行優(yōu)化场航。

由于封裝的是一個(gè)控制器,所以我決定在控制器loadView方法中禁用解壓縮廉羔,在delloc方法中恢復(fù)原設(shè)置:

1溉痢、首先在封裝的控制器中定義變量用于存儲原設(shè)置:

staticBOOLSDImageCacheOldShouldDecompressImages =YES;staticBOOLSDImagedownloderOldShouldDecompressImages =YES;

2、loadView中保存原設(shè)置并且禁用緩存解壓縮數(shù)據(jù):

SDImageCache *canche = [SDImageCache sharedImageCache];// SDImageCacheOldShouldDecompressImages = canche.shouldDecompressImages;// canche.shouldDecompressImages = NO;// 上面的被廢掉了,目前的寫法是:SDImageCacheOldShouldDecompressImages = canche.config.shouldDecompressImages;canche.config.shouldDecompressImages =NO;SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];SDImagedownloderOldShouldDecompressImages = downloder.shouldDecompressImages;downloder.shouldDecompressImages =NO;

3孩饼、dealloc中恢復(fù)原設(shè)置:

-(void)dealloc {? ? SDImageCache *canche = [SDImageCache sharedImageCache];? ? canche.config.shouldDecompressImages = SDImageCacheOldShouldDecompressImages;? ? ? ? SDWebImageDownloader *downloder = [SDWebImageDownloader sharedDownloader];? ? downloder.shouldDecompressImages = SDImagedownloderOldShouldDecompressImages;}

再次用instrument跑了一下髓削,方法果然有效,內(nèi)存徹底降下來了镀娶,如圖:

Snip20160725_13.png

當(dāng)然立膛,你也可以設(shè)置SDWebImage的其他參數(shù),比如是否緩存到內(nèi)存以及內(nèi)存緩存最高限制等梯码,來保證內(nèi)存安全:

shouldCacheImagesInMemory 是否緩存到內(nèi)存

maxMemoryCost? 內(nèi)存緩存最高限制

號外:蘋果官方給出了一個(gè)下載高清大圖的demo,內(nèi)存消耗很低宝泵。感興趣的朋友也可以看看:

https://developer.apple.com/library/ios/samplecode/LargeImageDownsizing/Introduction/Intro.html

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市轩娶,隨后出現(xiàn)的幾起案子儿奶,更是在濱河造成了極大的恐慌,老刑警劉巖鳄抒,帶你破解...
    沈念sama閱讀 217,185評論 6 503
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件闯捎,死亡現(xiàn)場離奇詭異,居然都是意外死亡嘁酿,警方通過查閱死者的電腦和手機(jī)隙券,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,652評論 3 393
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來闹司,“玉大人娱仔,你說我怎么就攤上這事∮巫” “怎么了牲迫?”我有些...
    開封第一講書人閱讀 163,524評論 0 353
  • 文/不壞的土叔 我叫張陵,是天一觀的道長借卧。 經(jīng)常有香客問我盹憎,道長,這世上最難降的妖魔是什么铐刘? 我笑而不...
    開封第一講書人閱讀 58,339評論 1 293
  • 正文 為了忘掉前任陪每,我火速辦了婚禮,結(jié)果婚禮上镰吵,老公的妹妹穿的比我還像新娘檩禾。我一直安慰自己,他們只是感情好疤祭,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,387評論 6 391
  • 文/花漫 我一把揭開白布盼产。 她就那樣靜靜地躺著,像睡著了一般勺馆。 火紅的嫁衣襯著肌膚如雪戏售。 梳的紋絲不亂的頭發(fā)上侨核,一...
    開封第一講書人閱讀 51,287評論 1 301
  • 那天,我揣著相機(jī)與錄音灌灾,去河邊找鬼搓译。 笑死,一個(gè)胖子當(dāng)著我的面吹牛锋喜,可吹牛的內(nèi)容都是我干的侥衬。 我是一名探鬼主播,決...
    沈念sama閱讀 40,130評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼跑芳,長吁一口氣:“原來是場噩夢啊……” “哼轴总!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起博个,我...
    開封第一講書人閱讀 38,985評論 0 275
  • 序言:老撾萬榮一對情侶失蹤怀樟,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后盆佣,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體往堡,經(jīng)...
    沈念sama閱讀 45,420評論 1 313
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,617評論 3 334
  • 正文 我和宋清朗相戀三年共耍,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了虑灰。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,779評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡痹兜,死狀恐怖穆咐,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情字旭,我是刑警寧澤对湃,帶...
    沈念sama閱讀 35,477評論 5 345
  • 正文 年R本政府宣布,位于F島的核電站遗淳,受9級特大地震影響拍柒,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜屈暗,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,088評論 3 328
  • 文/蒙蒙 一拆讯、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧养叛,春花似錦种呐、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,716評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽堕油。三九已至潘飘,卻和暖如春肮之,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背卜录。 一陣腳步聲響...
    開封第一講書人閱讀 32,857評論 1 269
  • 我被黑心中介騙來泰國打工戈擒, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人艰毒。 一個(gè)月前我還...
    沈念sama閱讀 47,876評論 2 370
  • 正文 我出身青樓筐高,卻偏偏與公主長得像,于是被迫代替她去往敵國和親丑瞧。 傳聞我的和親對象是個(gè)殘疾皇子柑土,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,700評論 2 354

推薦閱讀更多精彩內(nèi)容