天天看點

iOS開發那些事--性能優化–記憶體洩露問題的解決

記憶體洩漏問題的解決

記憶體洩漏(memory leaks)是當一個對象或變量在使用完成後沒有釋放掉,這個對象一直占有着這塊記憶體,直到應用停止。如果這種對象過多記憶體就會耗盡,其它的應用就無法運作。這個問題在c++、c和objective-c的mrr中是比較普遍的問題。

在objective-c中釋放對象的記憶體是發送release和autorelease消息,它們都是可以将引用計數減1,當為引用計數為0時候,release消息會使對象立刻釋放,autorelease消息會使對象放入記憶體釋放池中延遲釋放。

上代碼:

大家看看上面的3個方法會有什麼問題呢?如果代碼是基于arc的是沒有問題的,遺憾的是基于mrr,上面的代碼都存在記憶體洩漏的可能性。理論上講内 存洩漏是對象或變量沒有釋放引起的,但實踐證明并非所有的未釋放對象或變量都會導緻記憶體洩漏,這與硬體環境和作業系統環境有關,是以我們需要檢測工具幫助 我們找到這些“洩漏點”。

在xcode中提供了兩種工具幫助查找洩漏點:analyze和profile,analyze是靜态分析工具可以通過菜單 product→analyze啟動,為靜态分析之後的代碼畫面;profile是動态分析工具,這個工具叫“instruments”,它是xcode 內建在一起,可以在xcode中通過菜單product→profile啟動,instruments有很多trace template(跟蹤模闆)可以動态分析和跟蹤記憶體、cpu和檔案系統。

iOS開發那些事--性能優化–記憶體洩露問題的解決

我們可以兩個工具結合使用查找洩漏點,先使用analyze靜态分析查找可疑洩漏點,再用profile動态分析中的leaks和allocations跟蹤模闆進行動态跟蹤分析,确認這些點是否洩漏,或者是否有新的洩漏出現等。

其中的線段表明了程式執行的路徑,在這個路徑中,1:說明在25行objective-c對象引用計數是1,說明在這裡建立了一個 objective-c對象;2:說明在27行引用計數為1這個,該對象沒有釋放,懷疑有洩漏。這樣的說明已經很明顯的告訴我們問題所在了, [[nsarray alloc] initwithcontentsoffile:plistpath]建立了一個對象,并指派給 listteams屬性所代表的成員變量,然而完成了指派工作之後,建立的對象并沒有顯示地發送release和autorelease消息。代碼修改

我們看一下tableview:cellforrowatindexpath:方法中的疑似洩漏點行末尾的藍色圖示展開分析結果

iOS開發那些事--性能優化–記憶體洩露問題的解決

其中主要是說明uitableviewcell*類型的cell對象在64行有可能存在洩漏。在表視圖中 tableview:cellforrowatindexpath:方法是為表視圖單元格執行個體化并設定資料的,是以cell對象執行個體化後不能馬上 release,應該使用autorelease延遲釋放。可以在建立cell對象的時候發送autorelease消息,代碼修改如下:

我們看一下tableview:didselectrowatindexpath:方法中的疑似洩漏點有兩個,行末尾的圖示展開分析結果。

iOS開發那些事--性能優化–記憶體洩露問題的解決

 message對象建立之後沒有釋放,我們隻需要在[alert show]之後添加[message release]語句代碼就可以了。在objective-c中執行個體化對象有兩種方式:

①行所示以init-開頭構造方法,它的是在alloc之後調用該方法我們稱為“執行個體構造方法”,該方法建立對象所有權是調用者,調用者需要對它的 生命周期負責,具體說負責建立和釋放。而另一種是②行所示string-(去掉ns後類名)開頭方法,它是通過類直接調用我們稱為“類級構造方法”,該方 法是建立的對象所有權非調用者所有,調用者不無權釋放它,否則就會因過渡釋放而“僵屍化”。

uialertview*類型alert對象建立之後沒有釋放,我們隻需要在[alert show]之後添加[alert release]語句代碼就可以了,修改之後的代碼

上面介紹的使用analyze靜态分析查找可疑洩漏點,之是以稱為“可疑洩漏點”,但是這些點未必一定洩漏,确認這些點是否洩漏還要通過 profile動态分析工具instruments中的leaks和allocations跟蹤模闆,analyze靜态分析隻是一個理論上的預測過程。 通過菜單product→profile啟動, profile動态分析工具中選擇leaks模闆

iOS開發那些事--性能優化–記憶體洩露問題的解決

instruments中雖然是選擇了leaks模闆,但預設情況也會添加allocations模闆,基本上凡是分析記憶體都會使用 allocations模闆,它可以監控記憶體分布情況,選中allocations模闆(圖中①區域),右邊③區域會顯示随着時間的變化記憶體使用折線圖 表,同時在④區域會顯示記憶體使用的詳細資訊,其中剛剛對象配置設定情況。點選leaks模闆(圖中②區域),可以檢視記憶體洩漏情況,如果在③區域有紅線出現, 則有記憶體洩漏,④區域會顯示洩漏的對象。

iOS開發那些事--性能優化–記憶體洩露問題的解決

出現的洩漏是在點選表視圖中單元格測試tableview:didselectrowatindexpath:方法方法時候發生的,其中 nscfstring類型的對象發生了洩漏,nscfstring類型在nsfoundation中是nsstring*類型。點選洩漏對象前面的三角形 展開對象,可以看到它們的記憶體位址、占用位元組、所屬架構和響應方法資訊。

iOS開發那些事--性能優化–記憶體洩露問題的解決
iOS開發那些事--性能優化–記憶體洩露問題的解決

代碼77并不是洩漏點,而是其中的nsstring*類型對象在之後發生了洩漏,是以可以斷定是message對象之後沒有釋放導緻洩漏。我們修改代碼如下:

添加[message release]語句。很多人還會猜測alert對象(uialertview*)會有洩漏,是以重新運作instruments工具,反複點選單元格測 試,并未發現表示記憶體洩漏的紅線! instruments工具認為alert對象不釋放不會引起記憶體洩漏,如果我們想進一步評估它對于記憶體的應用,這個時候我們可以看看 allocations模闆的折線圖表,每次點選總占用記憶體數都有所增加,這說明alert對象沒有釋放雖然不是很嚴重,但是也會增加占用記憶體,是以 alert對象釋放也是必須的。

iOS開發那些事--性能優化–記憶體洩露問題的解決

這就是我們介紹的記憶體洩漏問題解決方法,事實上記憶體洩漏是極其複雜問題,工具使用是一方面,經驗是另一方面。提高經驗,然後借助于工具才是解決記憶體洩漏的根本。