開始之前:假如使用ARC的,就直接忽視此文。
這兩天項目的效能問題擺上檯面,由於長期未進行記憶體排查,現在的iPad版本已經有點過分慢了。
遂,連續查了好幾天記憶體。今天得閑,結合自己的使用,寫一下如何檢查記憶體泄露。
我所碰到的主要記憶體泄露的方式:
1、最常見的就是,申請了引用,然後最後忘記釋放。具體麼就是,使用OC的 alloc, retain, copy, new, C的malloc, realloc, C++ 的new等,然後沒有對應的release, free, delete。這是單向泄露。
2、retain cycle,對於OC這種使用計數的方式,可能會存在retain cycle。兩個條件,一、就是A中retain了B,B又retain了A,各自給對方計數增加,這個環可以變為很多層,就是A->B, B->C, C->D, .... Z->A,當然假如中介層越多,檢測難度就越大。二、計數減少的操作是在dealloc中,而dealloc被調用則需要計數為0。 這兩個條件相加,導致計數鎖定,記憶體泄露。
先講一下,如何尋找。
1、首先流量分析編譯,Analyze build,查看歸類當中的memory警告。
這個一般能發現局部變數中忘記release,或者被中途打斷release的。
2、然後就是直接使用Instruments中的leak監測。
申請了記憶體,然後已經沒有指向這塊記憶體的指標存在,可以認為是leak了。這個檢測一般是檢測這個狀態。
3、通過Instruments中allocation的mark heap。
進行不斷的重複操作,在每次情境結束後,標記記憶體。假如操作環境沒有泄露,記憶體增加應該是0。這個檢測是檢測標記點之間有哪些對象增加。另外,需要多mark幾次才會準確,不要mark兩次看到有記憶體增加就去找問題。
Instruments中都是可以看到其中存在什麼對象,調用曆史,呼叫堆疊。這時候大致確定在那個類當中的那個對象泄露了。
4、重載法。
雖然知道了哪個類泄露了,但是有時候並不知道具體是那邊的計數出現問題。我自己的方法是,假如是自己編寫的類,那就重載retain和release方法,然後加斷點。以此來監測是什麼地方retain了這個對象,卻沒有對應釋放。
然後就是進行下面的修改。
1、缺啥補啥。缺release的,就補release,缺free的就加個free。
2、合理使用autorelease。對於返回給上層使用的;或者alloc對象到release中間有return等打斷操作的。建議使用autorelease。
3、合理使用assign。retain cycle,本質就是多餘的雙向retain。打個比方就是應該確定哪個對象是根,哪一個是枝葉,枝葉不用去管理根,只需要知道根在那邊就可以了。所以把那些純粹是定位用的變數,屬性都改成assign方式,例如delegate。
over
PS:
1、假如對於Instruments的使用不是很清楚,可以看這個視頻 https://developer.apple.com/videos/wwdc/2010/?id=311 。不過貌似要登入。 當然搜尋教程,可以使用近乎萬能的google和無比強大的stackoverflow。
2、新的自動引用計數方式ARC,沒有仔細接觸過,不過已經不能自己編寫retain和release,非對應方式的泄露估計就沒有了。但是按照我自己粗淺的理解,ARC只是系統自己添加retain、release到合適的地方。所以,對於retain cycle的問題,應該還是存在的。然後,由於無法重載retain、release,我的重載法也是無效。
so,假如使用ARC的,就直接飄過吧。
3、系統庫自己本身也會泄露記憶體,so,查不到的就先擱著吧。
4、該去學習arc,轉換arc了。不然,記憶體問題會一直讓你煩死。。。
ps over