iOS記憶體洩漏檢測方法
阿新 • • 發佈:2018-11-19
常見洩漏的點
- 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