問題來源於SDWebImage這個庫。使用這個庫加載了網絡圖片以後,會將圖片存到NSCache中去,而後再顯示出來。可是在使用中,出現了一個最簡單卻又最粗暴的問題,內存的爆炸。在用它加載出圖片了以後,內存會發生驚人的爆炸。經過Instrument的leaks能夠看到在特定的某個圖片的加載中內存爆炸了,這塊空間的名字叫VM:CG raster data。百度了一下這個名字,只有一條記錄,簡直是逼我不再用百度的節奏。後來在谷歌上一找就是源源不斷的stackoverflow……
可是這一條記錄就是最重要的了。
這就是SDWebImage的GitHub:
https://github.com/rs/SDWebImage/issues/538php
這個項目自己是一個開源項目,因此當大多數人都遇到同一個問題的時候就會比較好解決一點。
在這裏我看到了無數和我遇到了相同問題的同志們,有些甚至更加的誇張。有大部分使用這個庫用來從加載GIF圖,加載了兩個GIF圖就能達到1G左右的內存,固然後面我就知道這個bug(也能夠不算是個bug)的厲害了……
在最後的大神站出來解決問題以前,還有一個哥們的回覆我以爲頗有記錄下來的必要:ios
Perhaps other people with the same problem could try what I tried. Keep in mind that I was using ARC.git
Run the profiler with the Leaks template and check for the allocation of your own classes in the Allocation Summary.
Dive into them and check how they are allocated, if there are leaks. Mind that a leak doesn’t show up in the Leaks instrument because you are using ARC. So Instruments could think everything is going oké but there still could be a leak somewhere. By diving in to the allocation of your own classes you could figure out what is going wrong.
Keep in mind that the retain/release count information is only provided when using the Leaks template and not while using the Allocations template.
My problem was that I was referencing instance variables and self directly from within blocks without reassigning them to __weak variables. When self is used within a block it will automatically be retained by ARC and sometimes never released. A weak reference prevents that from happening.github
For example, this is wrong:web
1 |
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification |
2 |
object:nil |
3 |
queue:nil |
4 |
usingBlock:^(NSNotification *note) { |
5 |
[self.view setContentOffset:CGPointMake(0.0, kKeyboardOffset) animated:YES]; |
6 |
}]; |
You should call self using a __weak reference like this:緩存
1 |
__weak YourViewControllerClass *weakSelf = self; |
2 |
[[NSNotificationCenter defaultCenter] addObserverForName:UIKeyboardDidShowNotification |
3 |
object:nil |
4 |
queue:nil |
5 |
usingBlock:^(NSNotification *note) { |
6 |
[weakSelf.view setContentOffset:CGPointMake(0.0, kKeyboardOffset) animated:YES]; |
7 |
}]; |
Since my app uses a lot of block’s I had a ton of leaks the Leaks instrument could not detect. When I fixed them the memory problem was gone.網絡
以上對於塊的循環引用已經不新鮮了,主要是他說若是你正在使用ARC而且但願經過Leaks來找到泄露的地方,程序會認爲一切泄露都是正常處理的。這也解釋了燦哥以前用instrument爲何一直看不到泄露的緣由。固然這可能只是一部分緣由吧,關於instrument的使用我會在以後寫出詳細的學習日誌,閱讀完官方的instrument guide document,那時候再找出真正的緣由。app
最後,大神終於站出來拯救世界了,(雖然我不明白爲何這麼久了纔有大神站出來)less
harishkashyap commented 16 days ago
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 memoryide
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.
1 |
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO]; |
2 |
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO]; |
首先二話不說,我把全部用到了decodedImageWithImage得地方都註釋掉了,跑起來一看,果真VM:CG raster data那塊已經不見了,內存的增加又回到了比較舒服的程度了。可是我仍是以爲奇怪呀,這個函數不可能就這麼廢卻還要存在呀,他說的意思大概是減壓縮圖片,並將圖片存到cache使得以後的加載更加快,效果更加好。可是問題就在於去壓縮這個操做,若是傳進的圖片分辨率特別的高,它的減壓縮會消耗大量的內存,按照帖子其餘回覆的綜合能夠大概得出結論就是他會將圖片的每個像素點都有一個空間存下它的各個通道值,雖然這個內存空間是因爲CG重繪的時候alloc出來的,因此是存在於VM裏的空間。所以這樣的處理會致使一個拇指大小的圖片均可能消耗上GB得內存。我也是醉了。
幾百K的圖片,分辨率達到3000+*2000+,就多消耗了40M內存,若是是GIF圖,又是幀數比較高,分辨率比較高的,就會出現一個GIF圖500M甚至上GB得奇葩現象= =(我突然以爲能夠在處理以前處理一下分辨率的問題,可是我又以爲這個方法只是對於顯示有幫助,緩存一樣仍是緩存下來了,貌似是隻有在retina屏幕的設備上才能看出這個的區別……)
另外中間有個小插曲,在一開始的profile過程當中,燦哥那裏用AM看內存消耗大概是60M左右(爆炸後),用Leaks看內存就到100M了,這二者顯示的內存不一樣,也是一個問題。
http://stackoverflow.com/questions/4596037/why-is-there-a-difference-between-the-reported-memory-usage-of-an-app-by-activit」
Activity Monitor is useless for development/debugging purposes. AM
is only useful if when you don’t have Instruments running already &
you see the RPRVT growing over time significantly. Even then, it is
just a symptom and may not indicate a real problem.AM is sort of summarizing a set of different memory related numbers.
It is a very rough number. The Allocations instrument is summarizing
exactly the set of allocations in your application (which, under Mac OS
X, could include both GC and non-GC allocations). Reduce the
allocations and the overall memory use will generally go down.Note that a system not under memory pressure will often not request
that applications give back memory. That is, you may not see a drop in
Activity Monitors numbers.
http://www.cocoachina.com/bbs/read.php?tid=266974
activity monitor 是程序在手機運行真正佔用的內存大小,達到系統內存的一半左右,就極可能被系統殺掉。建議檢查程序中耗用內存大的地方。allocations我的認爲是alloc/new所產生的內存大小。
這段話的意思大體是AM就是不許確的,只是用來看大概監控的,也無法定位內存問題,只有allocation或者leaks能夠看到程序中每一塊內存空間的實時狀況,另外也包括了Virtual Memory,因此可能會比AM裏看到的值更大。關於Virtual Mem和Real Mem的問題還會繼續跟進吧,其實真正運行時的內存消耗應當是以AM裏的爲準,VM不少並非在內存中開闢出來的空間,是系統在存儲空間裏爲內存開闢出來的空間,相似PC的虛擬內存。
Plus.(待研究)記錄一個小bug得解決辦法:
Xcode6.1運行程序後,左側Debug區域的Memory顯示空白
解決辦法:打開左側暫停符號右邊的那個下拉列表裏面的editSCheme 裏面有個選項叫叫作enable zoombie Objects 取消選中 ok
(關掉殭屍的其餘麻煩就沒辦法了,不過我以爲在這裏看到內存的監控也不是特別重要)
你好,我用你的方法把用到decodedImageWithImage的地方都註釋掉了,可是程序仍是會崩掉,仍是崩在了加載圖片的地方。你是直接把這個方法註釋掉而後沒有作其餘操做嗎?
報的錯是什麼。。用profile看的話是內存問題麼。
我後來沒有註釋掉,用了github上面的這個解決辦法
[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];
[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];
他就不會調用這個方法了= =
SD裏面的註釋這麼寫的。。
/**
* Decompressing images that are downloaded and cached can improve peformance but can consume lot of memory.
* Defaults to YES. Set this to NO if you are experiencing a crash due to excessive memory consumption.
*/
@property (assign, nonatomic) BOOL shouldDecompressImages;
固然若是這個更改了也沒用的話可能要根據你的crash來找問題了
我用的是新版的SDWebImage,沒有找到@property (assign, nonatomic) BOOL shouldDecompressImages;這個屬性,程序崩掉時就顯示收到內存警告,設備直接斷開鏈接了
在SDWebImage的Github裏的最新版本有這個屬性啊,SDImageCache和SDWebImageDownloader裏面都有
https://github.com/rs/SDWebImage/blob/master/SDWebImage/SDImageCache.h
我刪除了decodedImageWithImage 也添加了[[SDImageCache sharedImageCache] setShouldDecompressImages:NO];[[SDWebImageDownloader sharedDownloader] setShouldDecompressImages:NO];在每一個用到webimage的地方 爲何內存反而增長了