2009-03-05 49 views
14

我正在尋找主要來源(或非常好的解釋)來備份使用autorelease在爲iPhone編寫軟件時危險或過於昂貴的說法。爲什麼autorelease對iPhone應用程序特別危險/昂貴?

有幾位開發者提出這種說法,我甚至聽說蘋果公司不推薦它,但我還沒有能夠提供任何具體的資源來支持它。

SO引用:
autorelease-iphone
Why does this create a memory leak (iPhone)?

注:我可以看到,從概念的角度來看,這autorelease稍微比簡單的調用release更貴,但我不認爲小小的罰款足以讓蘋果推薦它。

什麼是真實故事?

回答

11

(?不能接受你自己的答案)

嘛,畢竟,我還是設法找到從蘋果開發者參考,加入靠近頁面底部的側面說明:

iPhone OS注意:由於在iPhone OS 應用在更 存儲受限環境中執行,所述 使用自動釋放池的不鼓勵在 碼方法或塊 (例如,環),其中一個 應用CREA測試許多對象。 相反,您應該儘可能明確地發佈 對象。

不過,這建議仔細使用autorelease,而不是完全避免它。

(現在對於我的評論)

聽起來好像有在保持池開銷一定的數量。我讀this article這會導致我儘可能地避免autorelease,因爲我更喜歡事情是一致的。如果你在autorelease下有一些內存,而其他內存是完全手動管理的,它可能會有點混亂。

+0

高興地幫助(給我一些東西來搜索:-) – TofuBeer 2009-03-05 05:58:00

+1

他們沒有提到的是很多基金會的調用autorelease對他們管理的對象,因此在緊密的循環中,你需要創建和管理你的類如果您正在處理適量的數據,則擁有自己的自動釋放池。 – rpetrich 2009-03-05 07:06:43

0

我強烈建議避免像瘟疫一樣自動釋放。內存管理錯誤是浪費大量時間和金錢的好方法,我曾經在舊的Mac應用程序中經歷過很多次這個過程的可疑榮譽,而且iPhone緊張的內存限制意味着你有要非常小心,否則應用程序就會不穩定並經常崩潰......就像去年夏天發佈的許多第一批應用程序一樣。

我發現編寫穩定的iPhone應用程序的唯一可靠方法就是自己管理所有的內存,並且一致地執行。即使你是你項目中唯一的程序員,你以後也會感謝你。如果你學會了用「爲你照顧所有東西」的語言進行編程,可能會很困難,但如果你對創建高質量的iPhone應用程序很認真,那麼確實值得學習。

5

我不同意那完全避免autorelease是明智的。

Cocoa Touch在內部非常頻繁地使用它,在很多情況下它是正確分配內存的唯一方式(一個很好的例子是可重用的表格視圖單元格)。如果你明白髮生了什麼,autorelease池是一個很好的工具,可供您使用。要記住的主要問題是,在運行循環稍後的某個點之前,塊纔會被釋放。如果你在沒有用戶交互的情況下運行一個緊密的循環,並且正在堆砌自動釋放塊,那麼最終會導致內存不足。

Autorelease不是垃圾收集的替代品(在iPhone SDK中不可用),並且可能導致令人討厭的懸掛指針錯誤(指針看起來仍然不錯,然後在某個不可預知的地方變得無效),但也是在編寫清晰易用的代碼時非常有用。考慮以下情況:

[aDictionary writeToFile: 
    [documentsDirectory stringByAppendingPathComponent:@"settings.plist"] 
       atomically:YES]; 

路徑字符串是作爲autorelease對象生成的。我們不需要創建一個臨時對象,所以我們避免了這種開銷(我們可能會忘記釋放它)。內存將被完全釋放(不泄漏),只是它會在運行循環中稍後發生。問問自己:在我回到用戶輸入之前,我會分配數百個這樣的數據嗎?如果不是(就像這裏的情況那樣),autorelease是一個很好的解決方案,事實上,這個用於處理路徑的NSString方法只能使用自動釋放內存。

我同意上面的海報,遵循慣例和一致是一個非常好的主意。

4

我傾向於避免在iPhone上使用autorelease(正如Jon指出的,如果沒有它,你總是不能這麼做),只是因爲我想知道我正在使用的對象是即時發佈的我不需要他們。內存限制是你在設備上面臨的最大問題之一,我相信它們是你在那裏發現的大部分崩潰問題的根源。

正如Apple強調的那樣,當您在任何類型的循環中使用自動釋放對象時,特別關心的一個問題是,它們會堆積在自動釋放池中。然後,您必須管理何時耗盡游泳池或創建/釋放游泳池。這樣做每次通過循環都可能會降低性能,但如果過多則不會導致危險的內存使用情況。我仍然在Molecules中對此進行了調整,因爲從Protein Data Bank導入大量(> 2 MB)文本文件時存在間歇性內存問題。我能夠通過減少自動釋放對象來提高性能,但無法完全消除它們。

另一個需要注意的地方是使用帶線程的自動釋放對象。如果可能的話,在處理在後臺線程上執行的方法時不要使用自動釋放對象,因爲該池可以隨機抽取。這會導致間歇性崩潰,這可能非常有趣追蹤。

9

這不是使用或不使用autorelease的問題,因爲在某些情況下,autorelease是唯一的方式,你會通過。問題應該是「爲什麼不在所有對象上使用autorelease,而不是使用保留和釋放?」。

要回答這個問題,你應該先了解一下autorelease的正確用法。假設您有一個具有兩個屬性的類:firstName和lastName。每個都有一個getter和一個setter。但你也需要,將返回全名,由這兩個字符串連接成一個全新的字符串的方法:

- (NSString *) fullName { 
    NSString str = [[NSString alloc]initWithFormat:@"%@ %@", firstName, lastName]; 
    // this is not good until we put [str autorelease]; 
    return str; 
} 

什麼是錯的畫面?返回字符串的引用計數爲1,所以如果你不想泄漏,調用者應該在他完成時釋放它。從來電者的角度來看,他只是要求物業價值fullName。他沒有意識到他得到了一個全新的對象,他應該在使用後釋放它,而不是對該類內部持有的NSString的引用!

如果我們在返回之前放置[str release],字符串將被銷燬,並且該方法將返回垃圾!這是我們使用[str autorelease]的地方,以便稍後標記對象以便發佈(通常在事件處理完成時)。這樣調用者可以獲得他的對象,並且不必擔心他是否應該釋放它。

約定是在方法將其返回給調用方之前,在新對象上調用autorelease。例外情況是名稱以alloc,newcopy開頭的方法。在這種情況下,呼叫者知道爲他們創建了一個全新的對象,他們有義務調用該對象的釋放。

完全用autorelease替換release是一個壞主意,因爲對象會很快堆積並堵塞內存,特別是在循環中。 iPhone上的資源是有限的,所以爲了最大限度地減少內存佔用,完成它之後立即釋放對象是您的職責。