內存洩露問題是每個app都必須關注的問題,關系到線上的穩定性和性能。內存洩露會導致:
由於內存資源不足發生難以排查的線上bug
由於被洩露對象的存在導致的一些業務bug,比如洩露的對象仍在接受全局通知
性能問題,導致用戶使用app時越來越卡
內存洩露發現分成靜態掃描和運行時檢測,本文主要講運行時檢測。
靜態掃描
靜態掃描的工具:
xcode analyzer
OCLint
Infer
運行時動態檢測
由於靜態掃描不能發現所有的內存洩露問題,所以運動時檢測是必不可少的。
Allocation
Xcode的Allocation可以通過比較不同時間段的對象,分析出是否發生了內存洩露。但是前提是每個頁面的命名要符合規范,比如寶貝詳情頁的所有對象都是應用前綴+寶貝詳情頁面前綴+具體對象名,這樣才退出頁面的時候才能知道相應的對象是否被釋放了,因為stack最底部的頁面的對象常駐在內存中。
Allocation通過和Monkey配合,在回歸測試的時候,自動運行並通過計算內存占用率可以判斷出新的開發版本是否發生了內存洩露,但是無法知道具體是哪個對象沒有釋放,只能是全局的判斷。
MLLeaksFinder
https://github.com/Zepo/MLeaksFinder
非常實用的內存洩露檢查工具,主要原理是UINavigationController在pop頁面的時候,可以預測出被pop的頁面將被釋放,所以在一段時間後(3s)對這個對象進行斷言判斷,如果沒有被釋放的話程序就會中斷,還可以掃描view hierarchy,或者自定義掃描需要的對象。
相比Allocation,最大的好處就是
及時發現正在開發的頁面是否發生了內存洩露,及時排查,而不是在回歸測試的時候才發現
如果應用中的每個頁面都有相應配置的URL scheme的話,那麼把所有頁面的url寫在配置文件中,在回歸測試的時候,代碼裡自動push每個url的頁面,可以做到完整地回歸所有頁面,又免去了Allocation手動點擊各個頁面的繁瑣。
如果嫌MLLeaksFinder代碼太多,可以自己實現一個精簡版的,原理比較簡單,代碼寫起來很少。
如何排查
上述的各種方法發現了內存洩露後,排查並解決才是最關鍵的一步。根據洩露的對象,重點排查block和兩個以上對象循環引用的情況。
如果是ViewController發生內存洩露,重點查看ViewController裡面的block是否忘記聲明weak了,因為ViewController被其他對象持有的情況不常見。如果是用RAC的話,記得weakly和strongly要成對出現,否則會發生內存洩露。
最常發生的是View的內存洩露問題,首先查看是發生內存洩露的view之間是否有delegate的關系,如果有的話看看delegate屬性有沒有聲明weak
由於service或者讀取緩存等異步操作引起的內存洩露問題
總結
內存洩露問題主要還是靠編碼時的規范,靜態掃描能解決一部分問題,動態掃描是最後的保證。而排查內存洩露經驗很重要。