因近期項目需要開發(fā)布會,所以花了幾天時間排查了項目里面的問題。發(fā)現(xiàn)了項目中存在著比較嚴(yán)重的內(nèi)存泄漏的問題。也借著這樣的機會查看了一下iOS內(nèi)存泄漏的原因以及排查方式。
排查方式
Xcode提供了內(nèi)置的Instruments工具,幫助我們?nèi)ヅ挪閮?nèi)存泄漏的問題,但是說實話,自帶的排查工具排查起來真的是比較費時。因此,我在查詢一些iOS內(nèi)存泄漏監(jiān)測自動化的文章時候發(fā)現(xiàn)了一些比較好用的工具,一個是Facebook開源的三劍客(FBRetainCycleDetector,FBAllocationTracker,FBMemoryProfiler),另外的則是微信閱讀團隊的MLeaksFinder。
關(guān)于 MLeaksFinder 這里有兩篇其官方提供的文章介紹:
簡單來說,MLeaksFinder 是從 UIViewController 入手。當(dāng)一個UIViewController 被 pop 或 dismiss 后,該 UIViewController 包括它的 view,view 的 subviews 等等將很快被釋放(除非你把它設(shè)計成單例,或者持有它的強引用,但一般很少這樣做)。只需在一個 ViewController 被 pop 或 dismiss 一小段時間后,看看該 UIViewController,它的 view,view 的 subviews 等等是否還存在。
MLeaksFinder 的原理非常簡單而且有效,幫助我排查了 App 中存在的不少內(nèi)存泄漏問題,而且對于整個應(yīng)用基本零侵入,不需要做任何的配置與修改。使用方法也異常簡單(pod 'MLeaksFinder'),無需添加任何代碼,也無需導(dǎo)入任何頭文件。
Xcode內(nèi)置的工具排查
1.靜態(tài)內(nèi)存分析


靜態(tài)分析的方法能夠發(fā)現(xiàn)大部分的問題,但是使用靜態(tài)分析,并不能完全的排查到所有的內(nèi)存泄漏問題,因此我們需要使用Leaks進行動態(tài)內(nèi)存分析。
2.動態(tài)內(nèi)存分析


當(dāng)我們打開Instruments之后,我們可以看到項目已經(jīng)自動啟動了,因為Leaks是動態(tài)監(jiān)測,所以當(dāng)我們進行操作的時候,可以檢測項目其他界面是否存在著內(nèi)存泄漏。




iOS內(nèi)存泄漏原因分析
- block的循環(huán)引用
- delegate循環(huán)引用問題
- 定時器(NSTimer)的不合理的使用
- 加載大量圖片導(dǎo)致內(nèi)存暴漲
Block的使用
使用block的時候,可能經(jīng)常會碰到的一個問題就是block體內(nèi)使用了self.xx,從而相互強指向,造成了循環(huán)引用。
解決方法:
//MRC下代碼如下
__block Viewcontroller *weakSelf = self;
//ARC下代碼如下
__weak Viewcontroller *weakSelf = self;
當(dāng)然現(xiàn)在一般的項目,基本上都是使用的ARC來管理內(nèi)存的。當(dāng)然,并不是所有的block都會造成循環(huán)引用,例如使用系統(tǒng)自帶的UIView 的Blcok,就不會產(chǎn)生循環(huán)引用,這里就不做深層次的探究了。
delegate的使用
使用strong進行修飾的時候,對象會強引用delegate,外界無法銷毀delegate對象,會導(dǎo)致循環(huán)引用,這時候我們就可以使用weak進行修飾,weak修飾的對象在釋放后,指針地址會被置為nil,是一種弱引用。
定時器(NSTimer)的使用

不使用 NSTimer的時候注意要銷毀NSTimer對象。
[timer invalidate];
timer = nil;
加載大量圖片
1.加載重復(fù)的圖片,最好使用`imageNamed`的方式加載。
2.當(dāng)你不需要重用該圖像,或者你需要將圖像以數(shù)據(jù)方式存儲到數(shù)據(jù)庫,又或者你要通過網(wǎng)絡(luò)下載一個很大的圖像時,請盡量使用`imageWithData`的方式加載圖像。