1. 程式人生 > >iOS記憶體洩漏檢測方法

iOS記憶體洩漏檢測方法

常見洩漏的點
  • Retain Cycle,Block強引用
  • NSTimer釋放不當
  • 第三方提供方法造成的記憶體洩漏
  • CoreFoundation方式申請的記憶體,忘記釋放

 

  1. Block引用記憶體洩漏問題:

[cell setSelectTagCityBlock:^(NSIndexPath *indexPath, NSInteger index){
        [self tableView:_tableViewCityList didSelectRowAtIndexPath:indexPath index:index];
    }];

   利用__weak防止Block迴圈引用方法:

//建立__weak弱引用,防止強引用互相持有
__weak __typeof(self)weakSelf = self;
AFNetworkReachabilityStatusBlock callback = ^(AFNetworkReachabilityStatus status) {
    //建立區域性__strong強引用,防止多執行緒情況下weakSelf被析構
     __strong __typeof(weakSelf)strongSelf = weakSelf;
    strongSelf.networkReachabilityStatus 
= status; if (strongSelf.networkReachabilityStatusBlock) { strongSelf.networkReachabilityStatusBlock(status); } }; weak 本身是可以避免迴圈引用的問題的,但是其會導致外部物件釋放了之後,block 內部也訪問不到這個物件的問題,我們可以通過在 block 內部宣告一個 strong 的變數來指向 weakObj,使外部物件既能在 block 內部保持住,又能避免迴圈引用的問題 block 本身無法避免迴圈引用的問題,但是我們可以通過在 block 內部手動把 blockObj 賦值為 nil 的方式來避免迴圈引用的問題。另外一點就是 block 修飾的變數在 block 內外都是唯一的,要注意這個特性可能帶來的隱患。

  

  2. Timer不被釋放引起的記憶體洩漏:

_timer = [NSTimer timerWithTimeInterval:[refreshTime integerValue]
                                             target:self
                                           selector:@selector(doFSearchDoubleBackNumberRequest:)
                                           userInfo:searchResult
                                            repeats:NO];
            [[NSRunLoop mainRunLoop] addTimer:_timer forMode:NSRunLoopCommonModes];
            

Timer 新增到 Runloop 的時候,會被 Runloop 強引用。
Timer 又會有一個對 Target 的強引用。
所以說如果不對Timer進行釋放,Timer的targer(self)也一直不會被釋放。
有時候我們我們對某個Timer的targer設定了nil。但沒設定[timer invalidate]。
其實這個物件還是沒被釋放的。timer對應的執行方法也一直會線上程中執行。容易造成記憶體洩露。

注:repeats:NO不會強引用

 

常規的監測方法
  • Analyze靜態分析 (command + shift + b)

    主要分析以下四種問題:

    1、邏輯錯誤:訪問空指標或未初始化的變數等;

    2、記憶體管理錯誤:如記憶體洩漏等;

    3、宣告錯誤:從未使用過的變數;

    4、Api呼叫錯誤:未包含使用的庫和框架。

    靜態分析結果會有警告提示

  

  • Instruments中的Leak動態分析記憶體洩漏

    product->profile ->leaks 開啟工具主視窗

  

  點選暫停,將滑鼠移到叉號上面點選鎖定,點選下方的“田”字格,選擇callTree,

  選擇中間的齒輪,選中選項中的 invert Call Tree 和Hide System Libraries。

Call Tree選項說明:
Separate by Thread:按執行緒分開做分析,這樣更容易揪出那些吃資源的問題執行緒。特別是對於主執行緒,它要處理和渲染所有的介面資料,一旦受到阻塞,程式必然卡頓或停止響應。
Invert Call Tree:反向輸出呼叫樹。把呼叫層級最深的方法顯示在最上面,更容易找到最耗時的操作。
Hide System Libraries:隱藏系統庫檔案。過濾掉各種系統呼叫,只顯示自己的程式碼呼叫。
Flattern Recursion:拼合遞迴。將同一遞迴函式產生的多條堆疊(因為遞迴函式會呼叫自己)合併為一條。

 

  雙擊左邊 Call Tree 窗口裡的任意一行,檢視記憶體洩漏的程式碼位置:

  

  • Allocation工具瞭解記憶體的分配情況

每次點選generations(是兩個時間標記之間所有仍然活著的物件的快照)生成快照,而且 Allocations 會記錄從上回記憶體快照到這次記憶體快照這個時間段內,新分配的記憶體資訊,數次 push 跟 pop 之後,記憶體還不斷增長,則有記憶體洩露。

  

 

參考Link:https://www.jianshu.com/p/9fc2132d09c7