[英]Use autorelease before adding objects to a collection?
我一直在查看StackOverflow上提出的問題,但是在Objective-C中有很多關於內存管理的內容,我找不到我想要的答案。
問題是,在將新創建的對象添加到集合(如NSMutableArray)之前,是否可以(並建議)調用autorelease? 或者我應該在添加后明確地發布它。 (我知道NSMutableArray會保留對象)
這說明了我的問題:
場景A(自動釋放):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
}
場景B(明確發布):
- (void) add {
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
[obj release];
}
我認為兩者都是正確的,但我不確定,我肯定不知道什么是優先的方式。
Objective-C大師可以對此有所了解嗎?
恕我直言,哪種方式是'正確的'是一個偏好的問題。 我並不反對主張不使用autorelease
的響應者,但我更傾向於使用autorelease
除非有極其令人信服的理由不這樣做。 我將列出我的理由,你可以決定它們是否適合你的編程風格。
正如查克所指出的,有一個半城市的傳說,使用自動釋放池有一些開銷。 這可能不是事實,這來自於使用Shark.app花費無數個小時來擠出代碼中的最后一點性能。 試圖對此進行優化是“過早優化”領域的深層原因。 如果且僅當Shark.app為您提供了硬數據,這可能是一個問題,您甚至應該考慮查看它。
正如其他人指出的那樣,一個自動釋放的對象“會在稍后發布”。 這意味着他們徘徊在周圍,占據記憶,直到“后來的點”滾動。 對於“大多數”情況,這是在運行循環休眠直到下一個事件(計時器,用戶點擊某些內容等)之前的事件處理過程的底部。
但有時候,你需要盡快擺脫那些臨時物體,而不是以后。 例如,您需要處理一個巨大的,多兆字節的文件,或數據庫中的數萬行。 發生這種情況時,您需要放置一個NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
在一個精心挑選的點,然后是[pool release];
在底部。 這幾乎總是發生在某種“循環批處理”中,因此它通常位於某個關鍵循環的開始和底部。 同樣,這應該是基於證據的,而不是基於預感的。 Instrument.app的ObjectAlloc是您用來查找這些問題點的方法。
easier to write leak-free programs. 不過,我更喜歡autorelease
release
主要原因是編寫無泄漏程序容易 。 circumstances. 簡而言之,如果您選擇使用release
路徑,則需要保證在情況下最終都會將release
發送到obj
。 雖然這看起來很簡單,但實際上卻很難做到。 舉個例子,舉個例子:
// array is an instance of NSMutableArray
MyClass *obj = [[MyClass alloc] init];
[array addObject:obj];
// Assume a few more lines of work....
[obj release];
現在想象一下,出於某種原因,某些東西,巧妙地違反了你的假設,即array
是可變的,可能是使用某種方法處理結果的結果,並且包含處理結果的返回數組被創建為NSArray
。 當您將addObject:
發送到該不可變的NSArray
,將拋出異常,並且您永遠不會發送obj
其release
消息。 或者也許在obj
是alloc
d和所需的 release
調用之間出現問題,就像你檢查一些條件並立即錯誤地return()
,因為它讓你想到以后必須 release
調用。
你剛剛泄露了一個物體。 並且可能已經簽了幾天試圖找出泄漏的地方和原因。 根據經驗,您將花費很多時間查看上面的代碼,確信它不可能是泄漏的來源,因為您非常清楚地發送obj
release
。 然后,幾天之后,你將體驗到只能被描述為宗教頓悟的東西,因為你對問題的原因有所啟發。
考慮autorelease
案例:
// array is an instance of NSMutableArray
MyClass *obj = [[[MyClass alloc] init] autorelease];
[array addObject:obj];
// Assume a few more lines of work....
現在,它不再重要,因為即使在非常不尋常或特殊的角落情況下,它幾乎不可能意外地泄漏obj
。
兩者都是正確的,並且會像你期望的那樣工作。
我個人更喜歡使用后一種方法,但僅僅因為我喜歡明確何時釋放對象。 通過自動釋放對象,我們所做的只是說“這個對象將在未來的某個任意點發布。” 這意味着你可以將自動釋放的對象放入數組中,銷毀數組,並且對象可能(可能)仍然存在。
使用后一種方法,對象將立即被陣列銷毀(假設沒有其他任何東西出現並在此期間保留它)。 如果我在一個內存受限的環境(比如iPhone)中我需要注意我正在使用多少內存,我將使用后一種方法,因此我沒有那么多的對象揮之不去一個NSAutoreleasePool。 如果內存使用對你來說不是一個大問題(通常也不適合我),那么任何一種方法都是完全可以接受的。
它們都是正確的但B可能是首選,因為它根本沒有開銷。 自動釋放導致自動釋放池負責對象。 這有一個非常小的開銷,當然,它會乘以所涉及的對象數量。
因此,對於一個對象A和B或多或少相同,但絕對不要在有大量對象添加到數組的場景中使用A.
在不同情況下,自動釋放可能會延遲並累積在線程末尾釋放許多對象。 這可能是次優的。 在沒有明確干預的情況下,無論如何都要注意自動釋放。 例如,許多getter以這種方式實現:
return [[myObject retain] autorelease];
因此,無論何時調用getter,都會將對象添加到自動釋放池中。
您可以隨時發送autorelease
消息,因為在應用程序的消息循環重復之前(即直到所有方法都響應用戶輸入完成執行)之后才會執行該操作。
http://macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=last&x-showcontent=text
你已經alloc
了對象,那么你的工作就是在某個時候釋放它。 兩個代碼片段僅以相同,正確的方式工作, autorelease
方式可能是較慢的對應方式。
就個人而言,我更喜歡autorelease
方式,因為它更容易打字,幾乎從不是瓶頸。
他們都很好。 有些人會因為“開銷”或某些事情而告訴你要避免自動釋放,但事實是,實際上沒有開銷。 繼續進行基准測試並嘗試找到“開銷”。 你避免使用它的唯一原因是像iPhone一樣處於記憶匱乏的境地。 在OS X上,你幾乎擁有無限的內存,所以它不會產生太大的影響。 只需使用最方便的方式。
我更喜歡A(自動釋放)以簡潔和“安全”,正如johne所說的那樣。 它簡化了我的代碼,我從來沒有遇到過它的問題。
也就是說,直到今天:在將塊添加到數組之前,我遇到了自動釋放塊的問題。 請參閱我的stackoverflow問題: [myArray addObject:[[objcBlock copy] autorelease]]在dealloc'ing數組時崩潰 (更新:結果問題在我的代碼中的其他地方,但仍然,自動釋放的行為有細微差別... )
聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.