你好,歡迎來到IOS教程網

 Ios教程網 >> IOS編程開發 >> IOS開發基礎 >> 使用SDWebImage和YYImage下載高分辨率圖,導致內存暴增的解決辦法

使用SDWebImage和YYImage下載高分辨率圖,導致內存暴增的解決辦法

編輯:IOS開發基礎

最近,收到朋友求助,說是有個控制器,一進去就crash,而且手機非常的燙,用instrument跑了跑,發現內存暴增幾百兆;如圖:

1278915-87dba9f8afd74039.png

  圖中可以看出,內存暴增的罪魁禍首是YYImage,再進一步定位問題,如圖:

1278915-4c27d79315c03ab6.png


  現在已經可以很清楚的知道,具體是哪些代碼導致內存飙升的,這個方法“YYCGImageCreateDecodeCopy”,主要是對圖像進行解壓縮操作;同樣的,換成SDWebImage,也出現了相同情況,由於某些原因,之後的分析都將以SDWebImage為例。
  先貼上朋友調用的SDWebImage的代碼:

[self sd_setImageWithURL:[NSURL URLWithString:imageUrl] placeholderImage:[UIImage imageNamed:@"defaulImage"] options:SDWebImageProgressiveDownload completed:nil];

instrument分析圖:

1278915-f157591f011528ec.png


代碼定位:

1278915-2a1700d5dbdedd80.png


  同樣的,也是在解壓縮的時候,出現內存飙升,但是為什麼會這樣呢?
  首先我想到“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的簡書
  1. 上一頁:
  2. 下一頁:
蘋果刷機越獄教程| IOS教程問題解答| IOS技巧綜合| IOS7技巧| IOS8教程
Copyright © Ios教程網 All Rights Reserved