引言
iOS 5.0之后apple引入了Xcode編譯器特性ARC(Automatic Reference Counting,自動引用計數)來幫助開發者管理內存,但為了追求app的高性能與減少安裝包大小,工作中很多時候需要我們手動管理內存。再牛的開發者也不能保證自己寫的code 100%沒有內存泄露,出現內存泄露不可怕,可怕的是我們時間與精力花了大把,但內存泄露依舊沒解決,即影響了工作效率也影響自己的心情。
那么我們如何檢測程序的內存泄漏呢?主要有以下兩種方式:
- 靜態分析(Analyse)
- 動態分析(Leaks)
靜態分析(Leaks)
- 主要是通過 Xcode 菜單欄 Product - Analyse,或者快捷鍵 CMD + Shift +B
- 缺陷:只能檢查編譯時期的內存泄漏,并不能檢測到所有的內存泄漏,主要是因為有些內存泄漏是發生在運行時,需要用戶操作才會產生。
動態檢測(Leaks)
- Instruments中的Leaks是因為有些內存泄露 是運行中用戶操作過程中產生的內存泄露
- 在真機或模擬器都可以動態檢測。
Leaks 介紹
從蘋果官方文檔可知,一個app的內存主要分3類
Leaked memory: Memory unreferenced by your application that cannot be used again or freed (also detectable by using the Leaks instrument).
Abandoned memory: Memory still referenced by your application that has no useful purpose.
Cached memory: Memory still referenced by your application that might be used again for better performance.
其中 Leaked memory 和 Abandoned memory 都屬于應該釋放而沒釋放的內存,都是內存泄露,而 Leaks 工具只負責檢測 Leaked memory,而不管 Abandoned memory。在 MRC 時代 Leaked memory 很常見,因為很容易忘了調用 release,但在 ARC 時代更常見的內存泄露是循環引用導致的 Abandoned memory,Leaks 工具查不出這類內存泄露,應用有限。對于 Abandoned memory,可以用 Instrument 的 Allocations 檢測出來。檢測方法是用 Mark Generation 的方式,當你每次點擊 Mark Generation 時,Allocations 會生成當前 App 的內存快照,而且 Allocations 會記錄從上回內存快照到這次內存快照這個時間段內,新分配的內存信息。缺點是需要重復操作,其無法及時得知泄漏
對于 Leaked memory,可以使用Leaks 工具檢測,適用于運行時的檢測
Leaks 工具
在Leaks中主要包含 4個統計項
- Statistics
- Call Trees
- Allocations List
- Generations
在 Leaks下方包含三個選項
Mark Generation:生成當前 App 的內存快照
-
Allocation Lifespan:篩選需要記錄的Allocation,一般我們只勾選Created & Persistent
- All Allocations:所有的
- Created & Persistent:創建且存活的
- Created & Destroyed:創建且被銷毀的
-
Allocation Type:記錄Allocation的類型,一般關注All Heap Allocations較多
- All Heap & Anonymous VM:所有真實內存和虛擬內存
- All Heap Allocations:所有真實內存
- All VM Regions:所有分配過的虛擬內存
Statistics 統計項
主要包含6個統計字段,分別對應的含義如下
- Category:對象類型,包含Core Foundation對象、OC類、內存塊
- Persistent:當前活躍的內存總量
- #Persistent:當前活躍的內存數量
- #Transient:已經釋放的內存申請數
- Total Bytes:總字節數
- #Total:申請內存總次數
Call Trees 統計項
這個功能是將列表展示類型切換成調用樹的形式,如下所示,有3個統計項:
- Bytes Used:相應方法使用的內存量
- Count:方法被調用的次數
- Symbol Name:方法名稱
對應的在Call Trees下方還有三個配置項,下面分別來介紹
-
【調用過濾】Call Tree:配置調用樹的顯示,一般勾選1、3、4、5
Instruments_05_03.png- 1、Separate by Category:按類別隔開,??后,可以更方便的看出是哪些類別的VM
- 2、Separate by Thread:按線程劃分
- 3、Invert Call Tree:反轉調用,通俗來說就是從上倒下跟蹤堆棧,例如FuncA{FunB{FunC}} 勾選此項后堆棧以C->B-A 把調用層級最深的C顯示在最外面
- 4、Hide System Libraries:隱藏系統方法,因為目前我們只關心自定義的方法,這個是必選的
- 5、Flatten Recursion:遞歸函數,每個堆棧跟蹤一個條目
-
【數據過濾】Call Tree Constraints:主要是對列表中的數據進行過濾,可以設置最大/最小的數量和字節數
Instruments_05_05.png 【庫/符號過濾】Data Mining:數據挖掘,簡單來說就是可以過濾掉不看的庫、符號調用,點擊Symbol、Library會自動把你選中的行的符號、庫加到小框中。例如選中start,點擊symbol,就自動過濾了start相關列
Allocations List 統計項
- Adress:內存塊的地址
- Category:對象的類型
- Timestamp:申請內存的時間
- Size:內存塊的大小
- Responsible Library:負責申請該內存的庫
- Responsible Caller:負責申請該內存的方法
Generations 統計項
在Allocation中,可以通過對每個動作的前后進行Mark Generation,用來對比內存的增加,可以定位到內存增加的具體方法和代碼所在位置。其中有4列統計項
- Snapshot:快照名
- Timestamp:快照時間
- Heap Growth:自上次快照以來的增長數量
- #Persistent:依舊存活的對象數量
使用
使用主要分兩部分
- 檢測內存泄漏
- 查看具體的內存泄漏情況
檢測內存泄漏
-
Xcode菜單 - Product - Profile - Leaks,然后運行程序,隨著對模擬器運行的App的操作,可以在Leaks中查看內存占用的情況。
Instruments_05_09.png -
其中? 表示 不存在內存泄漏,?表示存在內存泄漏,將豎線移動到內存泄漏點,然后選擇 統計項,如下所示
Instruments_05_10.png -
選擇底部的Call Tree在彈窗中選擇Invert Call Tree 和 Hide System Libraries,即可顯示出具體內存泄漏的代碼,點擊最左側的箭頭,可查看文件中具體的代碼
Instruments_05_11.png
查看內存泄漏引用圖
將Call Tree選項改為Cycles & Roots 即可查看,如下所示
參考文章
XCode內存泄漏檢測工具介紹-Instruments之Leaks
使用Instruments定位iOS應用的Memory Leaks
Xcode Instruments Leak解決內存泄漏問題
# iOS Instruments之Leaks
### Xcode Instruments系列之Leaks使用教程
# iOS開發之非常精準內存泄露檢測工具
# Find memory leaks