4

我有以下形式的ARC代碼:objective-c內存管理 - 對象保證存在多久?

NSMutableData* someData = [NSMutableData dataWithLength:123]; ...

CTRunGetGlyphs(run, CGRangeMake(0, 0), someData.mutableBytes); ...

const CGGlyph *glyphs = [someData mutableBytes]; ...

...後面的代碼讀取內存從glyphs,但沒有任何與someData,它不再被引用。請注意,CGGlyph不是對象類型,而是無符號整數。

難道我不必擔心someData的內存在我完成glyphs(實際上只是指向someData)之前可能會被釋放嗎?

所有這些代碼都在同一範圍內(即單個選擇器),並且glyphssomeData都在同一時間超出範圍。

PS在這個問題的早期草稿中,我提到了'垃圾收集',這並沒有真正適用於我的項目。這就是爲什麼下面的一些答案給予了與ARC下發生的事情同等的待遇。

+5

您是否真的在啓用GC的情況下運行?你不得不打開它,它已經(預先)棄用了。或者你在談論ARC,這不是GC? –

+0

喬希問一個好問題。 GC!= ARC。 – MikeS

+0

按要求更正。 – Merk

回答

1

截至2012年夏季的,東西都在變化爲該返回非對象類型的內部指針蘋果對象的過程。在release notes的山獅,蘋果說:

NS_RETURNS_INNER_POINTER

方法,返回指針(比目標C對象除外) 已裝飾着鏗鏘編譯器屬性 objc_returns_inner_pointer(與鏗鏘編譯時)以防止 編譯器主動釋放那些不再被引用的那些 消息的接收器表達式,而返回的 指針可能仍在使用中。

檢查NSData.h頭文件表明這也適用於iOS 6以上。

還要注意的是NS_RETURNS_INNER_POINTERclang規範定義爲__attribute__((objc_returns_inner_pointer)),這使得它使得

對象的生存期將延長至至少最早的:最後使用 返回指針,或從它派生的任何指針, 在調用函數中; 或自動釋放池被恢復到以前的狀態 。

注意事項: 如果你使用任何舊的然後山獅或iOS 6你仍然需要使用任何這裏討論的方法(例如,__attribute__((objc_precise_lifetime)))宣佈當地的NSData和NSMutableData對象時。

此外,即使使用最新的編譯器和Apple庫,如果您使用舊的或第三方庫的對象不裝飾他們的內部指針返回方法與__attribute__((objc_returns_inner_pointer))您將需要修飾您的本地變量聲明這樣的對象與__attribute__((objc_precise_lifetime))或使用答案中討論的其他方法之一。

2

以下是一般性答案,不一定反映Objective-C GC支持。但是,包括重新計數在內的各種GC實現可以被認爲是可達性,拋開怪癖。


在GC語言,一個目的是保證,只要它是Strongly-Reachable存在;這些Strong-Reachability圖的「根」可能因語言和執行環境而異。 「強」的確切含義也有所不同,但通常意味着邊是強參考。 (在手動參考計數場景中,每條邊都可以被認爲是來自給定「所有者」的無法匹配的「保留」。)

CLR/.NET上的C#就是一個這樣的實現,其中變量可以保留在範圍,但不能作爲可達性圖的「根」。見Systems.Timer.Timer類並查找GC.KeepAlive

如果定時器是在長時間運行的方法聲明中,使用保持活動,以防止垃圾收集的發生[計時器對象]的方法結束之前。

3

在實際的,真正的垃圾回收代碼可能是一個問題。如果對象不再有任何引用,對象可能會被釋放,並且如果您再也不使用它,編譯器可能會隨時丟棄引用。爲了達到最優化的目的,範圍僅僅是爲這種事情設置一個上限的方法,而不是絕對的方式。

您可以使用NSAllocateCollectable將生命週期計算附加到C原語指針,儘管它很混亂且稍微複雜。

垃圾收集從未在iOS中實現過,現在在Mac上不推薦使用(在this FAQ的底部引用),兩種情況都支持自動引用計數(ARC)。ARC增加了retain s和releases,它可以看到它們是隱含需要的。不幸的是,它可以執行一些以前不可能的巧妙技巧,比如從autorelease池中檢索對象,如果它們被用作返回結果的話。因此,這與垃圾收集方法具有相同的淨效果 - 對象可能在最終引用消失後的任何時候釋放。

一種解決方法是創建一個類,如:

@interface PFDoNothing 

+ (void)doNothingWith:(id)object; 

@end 

這是實現什麼也不做。完成使用內部存儲器後,將您的自動釋放對象發佈給它。 Objective-C的動態調度意味着編譯器優化調用是不安全的 - 它無法知道你(或KVO機制或任何其他actor)在運行時沒有做過像調用方法那樣的東西。

編輯:NSData是一種特殊情況,因爲它提供了直接的C級訪問對象保存的內存,所以至少找到GC情況的明確討論並不困難。儘管與上述相同,但請參閱this thread on Cocoabuilder,即不要使用垃圾回收,並且自動引用計數的行爲不同。

+1

我已經做了一些挖掘,並重新:「假設沒有手動池管理和其他一切正常,你的[NSMutableData dataWithLength:123]肯定會持續,只要當前ARC下的方法」,其他來源似乎不同意,包括上面的@CRD引用的討論,以及http://clang.llvm.org/docs/AutomaticReferenceCounting.html。 「...自動存儲持續時間的局部變量沒有精確的生命週期語義。」 – Merk

+0

@Merk我認爲你是對的,我以前的回答是錯誤的。因此,我編輯了它,以防止錯誤持續存在。向所有人道歉。 – Tommy

4

你是潛在無論你使用GC還是像其他人推薦的那樣使用GC。你正在處理的是內部指針,它不被認爲是,它在GC或ARC中一般都擁有引用 - 除非該實現具有特殊的外殼NSData。如果沒有自己的引用,GC或ARC可能會刪除該對象。你面臨的問題是內部指針特有的。

當你描述你的情況時,最安全的事情就是堅持真正的參考。您可以通過將NSData引用分配給實例變量或static(方法本地,如果您願意)變量,然後在完成內部指針時將nil分配給該變量來完成此操作。在static的情況下要小心併發!

實際上,你的代碼可能在GC和ARC中都可以工作,可能在ARC中更有可能,但是在編譯器改變的時候,或者可以想見咬你。對於一個變量聲明和一個額外任務的成本,您可以避免這個問題,便宜的保險。

[見this討論,ARC下壽命短的一個例子。]

+0

謝謝,那個牧場牧場的討論有所幫助。所以#1。有一個問題。 #2。有3種建議的方法可以解決這個問題:(a)你的伊娃爾建議(b)objc_precise_lifetime限定詞(c)在該函數結束時自動調用[someData self]。從清晰度和維護角度來看,你的伊娃建議可能是最簡單的。 – Merk

+0

我在下面的答案討論了Apple最近處理內部指針的方法。如果你喜歡它,歡呼聲並加油。 – Merk