iOS學習——內存泄漏檢查及緣由分析

  項目的代碼不少,前兩天老大忽然跟我說項目中某一個ViewController的dealloc()方法沒有被調用,存在內存泄漏問題,須要排查緣由,解決內存泄漏問題。因爲剛加入項目組不久,對出問題的模塊的代碼還不太熟悉,因此剛拿到問題時以爲很棘手,再加上做爲一個iOS菜鳥,對內存泄漏的排查方法和緣由確實基本上不了解。因此,也藉着這樣的機會,我研究了一下關於iOS開發中內存泄漏的排查方法和緣由分析。xcode

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

  • 內存溢出 (out of memory):是指程序在申請內存時,沒有足夠的內存空間供其使用,出現out of memory。通俗理解就是內存不夠,一般在運行大型軟件或遊戲時,軟件或遊戲所須要的內存遠遠超出了你主機內安裝的內存所承受大小,就叫內存溢出。
  • 內存泄露( memory leak):是指程序在申請內存後,沒法釋放已申請的內存空間,一次內存泄露危害能夠忽略,但內存泄露堆積後果很嚴重,不管多少內存,早晚會被佔光。

1、排查方法

  咱們知道,iOS開發中對內存管理的要求很是嚴格,一旦存在內存泄漏,後果是很是嚴重的,會致使程序很是容易崩潰。儘管目前iOS開發基本上都是採用的ARC方式進行內存管理,可是一不當心就會存在內存泄漏的問題。工具

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

1.1 靜態內存泄漏分析方法

  經過xcode打開項目,而後點擊product-->Analyze,以下圖左側的圖所示,這樣就開始對項目進行靜態內存泄漏分析,分析結果以下圖右側的圖所示。根據分析結果進行休整以後在進行分析就行了。spa

       

  靜態分析方法能發現大部分的問題,可是隻能是靜態分析結果,有一些並不許確,還有一些動態分配內存的情形並無進行分析。因此僅僅使用靜態內存泄漏分析獲得的結果並非很是可靠,若是須要,咱們須要將對項目進行更爲完善的內存泄漏分析和排查。那就須要用到咱們下面要介紹的動態內存泄漏分析方法Instruments中的Leaks方法進行排查。3d

1.2 動態內存泄漏分析方法

  分析內存泄露不能把全部的內存泄露查出來,有的內存泄露是在運行時,用戶操做時才產生的。那就須要用到Instruments了。具體操做是經過xcode打開項目,而後點擊product-->profile,以下圖左側圖所示。代理

       

  按上面操做,build成功後跳出Instruments工具,如上圖右側圖所示。選擇Leaks選項,點擊右下角的【choose】按鈕,這時候項目程序也在模擬器或手機上運行起來了,在手機或模擬器上對程序進行操做,工具顯示效果以下:code

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

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

2、內存泄漏的緣由分析

  在目前主要以ARC進行內存管理的開發模式,致使內存泄漏的根本緣由是代碼中存在循環引用,從而致使一些內存沒法釋放,這就會致使dealloc()方法沒法被調用。主要緣由大概有一下幾種類型。

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,不然會形成循環引用,內存沒法釋放。

相關文章
相關標籤/搜索