內存泄漏檢查及原因分析

首先,補充兩個基本概念的解釋:

  • 內存溢出 (out of memory):是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory , 通俗理解就是內存不夠 , 比如:
int A = 100000000000000000000000000;
//定義A的時候會向內存申請一個int的空間,很明顯賦值已經超出了int范圍 所以會造成內存溢出
  • 內存泄露( memory leak):是指程序在申請內存后,無法釋放已申請的內存空間,一次內存泄露危害可以忽略,但內存泄露堆積后果很嚴重,無論多少內存,遲早會被占光。

一、排查方法

我們知道,iOS開發中對內存管理的要求非常嚴格,一旦存在內存泄漏,后果是非常嚴重的,會導致程序非常容易崩潰。盡管目前iOS開發基本上都是采用的ARC方式進行內存管理,但是一不小心就會存在內存泄漏的問題。

首先,我們需要定位內存泄漏的問題,目前比較常用的內存泄漏的排查方法有兩種,都在xcode中可以直接使用:靜態分析方法(Analyze)和動態分析方法(Instrument的leak)。

1.1 靜態內存泄漏分析方法

通過xcode打開項目,然后點擊product-->Analyze,如下圖所示,這樣就開始對項目進行靜態內存泄漏分析.


1.png

分析結果如下圖所示。根據分析結果進行休整之后在進行分析就好了。


2.jpg

靜態分析方法能發現大部分的問題,但是只能是靜態分析結果,有一些并不準確,還有一些動態分配內存的情形并沒有進行分析。所以僅僅使用靜態內存泄漏分析得到的結果并不是非常可靠,如果需要,我們需要將對項目進行更為完善的內存泄漏分析和排查。那就需要用到我們下面要介紹的動態內存泄漏分析方法Instruments中的Leaks方法進行排查。
1.2 動態內存泄漏分析方法

分析內存泄露不能把所有的內存泄露查出來,有的內存泄露是在運行時,用戶操作時才產生的。那就需要用到Instruments了。具體操作是通過xcode打開項目,然后點擊product-->profile,如下圖所示。


3.jpg

按上面操作,build成功后跳出Instruments工具,如下圖所示


4.png

選擇Leaks選項,點擊右下角的【choose】按鈕,這時候項目程序也在模擬器或手機上運行起來了,在手機或模擬器上對程序進行操作,工具顯示效果如下:
5.png

點擊左上角的紅色圓點,這時項目開始啟動了,由于leaks是動態監測,所以手動進行一系列操作,可檢查項目中是否存在內存泄漏問題。如圖所示,橙色矩形框中所示綠色為正常,如果出現如右側紅色矩形框中顯示紅色,則表示出現內存泄漏。


6.png

選中Leaks Checks,在Details所在欄中選擇CallTree,并且在右下角勾選Invert Call Tree 和Hide System Libraries,會發現顯示若干行代碼,雙擊即可跳轉到出現內存泄漏的地方,修改即可。


7.png

二、內存泄漏的原因分析

2.1 ViewController中存在NSTimer

如果你的ViewController中有NSTimer,那么你就要注意了,因為當你調用

[NSTimer scheduledTimerWithTimeInterval:1.0 
                                 target:self 
                               selector:@selector(updateTime:) 
                               userInfo:nil 
                                repeats:YES];

時的 target:self 就增加了ViewController的return count,如果你不將這個timer invalidate,將別想調用dealloc。

2.2 ViewController中的代理delegate

一個比較隱秘的因素,你去找找與這個類有關的代理,有沒有強引用屬性?如果你這個VC需要外部傳某個Delegate進來,來通過Delegate+protocol的方式傳參數給其他對象,那么這個delegate一定不要強引用,盡量assign或者weak,否則你的VC會持續持有這個delegate,直到它自身被釋放。

2.3 ViewController中Block

這個可能就是經常容易犯的一個問題了,Block體內使用實例變量也會造成循環引用,使得擁有這個實例的對象不能釋放。因為該block本來就是當前viewcontroller的一部分,現在蓋子部門又強引用self,導致循環引用無法釋放。 例如你這個類叫OneViewController,有個屬性是NSString *name; 如果你在block體中使用了self.name,或者_name,那樣子的話這個類就沒法釋放。 要解決這個問題其實很簡單,就是在block之前申明當前的self引用為弱引用即可。

//MRC下代碼如下
__block Viewcontroller *weakSelf = self;
//ARC下代碼如下
__weak Viewcontroller *weakSelf = self;
2.4 ViewController的子視圖對self的持有

這個問題也是我的項目中內存泄漏的問題所在。我們有時候需要在子視圖或者某個cell中點擊跳轉等操作,需要在子視圖或cell中持有當前的ViewController對象,這樣跳轉之后的back鍵才能直接返回該頁面,同時也不銷毀當前ViewController。此時,你就要注意在子視圖或者cell中對當前頁面的持有對象不能是強引用,盡量assign或者weak,否則會造成循環引用,內存無法釋放。

不足之處 敬請指出 謝謝!!!

?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容

  • 內存管理 簡述OC中內存管理機制。與retain配對使用的方法是dealloc還是release,為什么?需要與a...
    丶逐漸閱讀 1,991評論 1 16
  • *面試心聲:其實這些題本人都沒怎么背,但是在上海 兩周半 面了大約10家 收到差不多3個offer,總結起來就是把...
    Dove_iOS閱讀 27,205評論 30 471
  • 前言 內存泄露是一個相對挺嚴重的問題,可是它的存在未引起足夠的重視,如果程序運行時一直分配內存而不及時釋放無用的內...
    進無盡閱讀 1,801評論 0 5
  • 一:block內部可能存在的self的集中使用情況 (1)什么時候在 block 里面用 self,不需要使用 w...
    雷鳴1010閱讀 1,254評論 0 1
  • 和張院長合影
    博怡閱讀 167評論 0 0