12

autorelease用於返回的函數對象,因此調用者不擁有所有權,被調用者將在未來釋放該對象。ARC和autorelease

但是,ARC能夠計算調用者的所有權並在使用後釋放它,也就是說,它可以像C++中的智能指針一樣行爲。使用ARC,它可以擺脫autorelease,因爲autorelease是非確定性的。

我問這個問題的原因是,我看到ARC中的返回對象調用dealloc比非ARC代碼更早。這讓我認爲ARC可以像智能指針那樣行事,並且可以讓autorelease變得毫無用處。這是真的還是可能的?我可以考慮的autorelease有用性唯一的事情是在多線程或網絡代碼中,因爲當對象傳遞時可能不容易計算所有權。

感謝您的想法。

這裏是新的編輯做出明確一點:

與自動釋放

+ (MyClass*) myClass 
{ 
    return [[[MyCClass alloc] init] autorelease]; 
} 

- doSomething 
{ 
    MyClass *obj = [MyClass myClass]; 
} 

弧:

+ (MyClass*) myClass 
{ 
    return [[MyCClass alloc] init]; // no autorelease 
} 

- doSomething 
{ 
    MyClass *obj = [MyClass myClass]; 
    // insert [obj release] 
} 

所以,我們真的不需要自動釋放。

ARC:

-somefunc { 
    id obj = [NSArray array]; 
    NSLog(@"%@", obj); 
    // ARC now calls release for the first object 

    id obj2 = [NSArray array]; 
    NSLog(@"%@", obj2); 
    // ARC now calls release for the second object 
} 

自動釋放:ARC和自動釋放之間

+4

自動釋放是不是在所有非確定性。池在運行循環的每次旋轉的底部向每個包含的對象發送'release'。 –

+0

@JoshCaswell我在autorelease相關代碼中看到一些subtl錯誤。當代碼調用一個對象時,它實際上是「釋放」,但釋放是在運行循環的每次旋轉的底部完成的。當代碼遷移到ACR時,它崩潰。原因是ARC縮短了物體的壽命。 – user2573923

+0

@ user2573923它是這樣做的,但除非使用'weak'引用,否則應該無關緊要,在使用它們之前,應始終在本地將其轉換爲'strong'。 –

回答

4

差異代碼解釋

-somefunc { 
    id obj = [NSArray array]; 
    NSLog(@"%@", obj); 

    id obj2 = [NSArray array]; 
    NSLog(@"%@", obj2); 
} 
// Objects are released some time after this 

基本上ARC工作一次一個變量沒有在一個範圍不再使用,而autorelease一直等到它到達主循環,然後在池中的所有對象上調用release。 ARC用於裏面的的範圍,autorelease用於以外的函數的作用域。

+2

第二個例子是不正確的。 – 2013-07-11 19:11:23

+0

我認爲ARC可以像智能點一樣取代autorelease。你不需要autorelease一個返回的對象,相反,當調用者調用該函數時,ARC可以保留它。在調用者完成對象之後,ARC將其釋放。將來你不需要等待。它是非確定性的並且是不好的。 – user2573923

+0

@ H2CO3'//物體在這之後被釋放一段時間就足夠了,不是嗎? – Tommy

20

作爲機制的自動釋放仍然是ARC使用的,此外,ARC編譯代碼被設計爲無縫地與MRC編譯代碼互操作,所以自動釋放機器就在附近。

首先,不要以參考計數的方式來考慮所有權利益 - 只要在對象中存在已聲明的所有權利益,那麼該對象就會生存,當沒有所有權利益時就會被銷燬。在MRC中,您通過使用retain或創建新對象來聲明所有權利益;並且您使用release放棄所有權利益。

現在,當被調用方法創建一個對象並希望將其返回給其調用方時,被調用方正在離開,因此它需要放棄所有權利益,因此調用方需要聲明其所有權利益或者對象可能被銷燬。但是存在一個問題,即被調用者在調用者接收對象之前完成 - 因此當調用者放棄其所有權利益時,該對象可能在調用者有機會聲明其興趣之前被銷燬 - 不好。

兩種解決方案來解決這個問題:

1)方法被聲明爲從被叫至主叫其返回值轉移股權 - 這是用於initcopy等模型。 方法。被調用者從不通知它放棄其所有權利益,被調用者從不聲明所有權利益 - 通過協議,調用方只是接管所有權利益和稍後放棄它的責任。

2)該方法被聲明爲返回一個值,其中調用方沒有所有權利益,但是其他人將在一段短時間內維持所有權利益 - 通常直到當前運行循環週期結束。 如果調用者想要使用比這更長的返回值,那麼必須聲明自己的所有權利益,否則它可以依賴於擁有所有權利益的其他人以及因此留下的對象。

的問題是,誰可以說,「有人」是誰在維護所有者權益?它不可能是被調用方法,因爲它即將消失。輸入「autorelease pool」 - 這只是一個對象,任何人都可以將所有權轉移給對象,以便對象留在一段時間。自動釋放池在被指示的時候會以這種方式放棄它傳遞給它的所有對象的所有權 - 通常在當前運行循環結束時。

現在,如果上面讓任何意義(即,如果我解釋清楚),你可以看到,方法(2)是不是真的需要,你總是可以使用方法(1); ,它的一個重要,MRC下,這是爲程序員大量的工作 - 從法收到的每個值附帶了一個必須加以管理,並在某些時候放棄的所有者權益 - 生成的字符串只是輸出它?那麼你需要放棄你對這個臨時絃樂的興趣......所以(2)讓生活變得更容易。

一個另一方面電腦只是快速白癡,和計數的東西並插入代碼,以放棄代智能程序員的所有者權益是他們都非常適合。所以ARC不需要需要的自動釋放池。但它可以讓事情變得更容易,更高效,並在後臺ARC優化它的使用 - 查看Xcode中的彙編程序輸出,您將看到類似於「retainAutoreleasedReturnValue」名稱的例程調用...

因此,您是正確的,它不是需要,但它仍然有用 - 但在ARC下,你可以(通常)忘記它甚至存在。

HTH超過它可能混淆了!

+0

謝謝。這非常有幫助。有了ARC,我認爲你的第一個解決方案就是不需要autorelease。我檢查了鏗鏘,它和你在這裏解釋的一樣。關於 「autorelasepool塊」(@autoreleasepool {...}) – user2573923

+0

信息https://developer.apple.com/library/ios/documentation/Cocoa/Conceptual/MemoryMgmt/Articles/mmAutoreleasePools.html#//apple_ref/doc/ UID/20000047-CJBFBEDI –

5

autorelease用於返回的函數對象,因此調用者不擁有所有權,被調用者將在未來釋放該對象。

如果自動發佈,它將被添加到autorelease池中。當自動釋放池被耗盡時,將執行延期釋放。一個函數/方法不需要返回一個自動釋放對象(例如它可能是沒有收到保留/自動釋放週期的伊娃)。

然而,ARC能夠計算呼叫者的所有權和使用後釋放,也就是說,它可以行爲就像++智能指針的溫度。使用ARC,它可以擺脫autorelease,因爲autorelease是非確定性的。

它具有潛力來。沒有保證。這裏最大的問題是編譯器不知道/關心任意調用的返回對象的內存機制。它不能假設一個對象是如何被返回的,因爲ARC是一個在MRC之前的新增加。這很重要,因爲它使ARC程序與使用手動保留/釋放的程序兼容。例如,Foundation.framework可能使用ARC,或者它可能使用MRC,或者它可能同時使用兩者。它也可能會調用使用較舊工具鏈構建的API。所以這有利於保持大量現有的代碼可用。

我問這個問題的原因是我看到ARC中的返回對象調用dealloc比非ARC代碼更早。

有一種返回對象的可選方法 - 請參閱CRD關於程序集的回答(+1)以及編譯器插入的用於執行引用計數操作的調用,例如, retainAutoreleasedReturnValue

在任何情況下,ARC都不能保證壽命總是會減少。懂得執行他們程序的程序員可以最大限度地減少生命週期和參考操作,因爲ARC具有更嚴格的生命週期和所有權要求。

這讓我認爲ARC可以像智能指針那樣行事,並且可以讓autorelease變得毫無用處。這是真的還是可能的?

從理論上講,我不明白爲什麼自動釋放池無法免掉了一個新的系統。然而,我認爲現有的代碼太多依賴於autorelease池來解除限制 - 我認爲他們需要逐步採用新的可執行格式(ObjC垃圾收集的情況就是這樣),並審查大量現有的API,並且這樣的重大過渡計劃才能取得成功。此外,一些API可能只需要刪除。應用程序接口可能需要加強所有權才能完成,但其中大部分在已經被移植到ARC的程序中完成。哎呀,即使編譯器可以(擴展到)內部使用一種智能指針的形式來傳遞和返回objc類型,並且autorelease池可以在這樣的系統中被消除。同樣,這需要很多代碼才能被遷移。所以這樣的升級就像是一個ARC V2。

我能想到的有用性的自動釋放的唯一的事情是在MULTIP線程或網絡代碼,因爲它可能是不容易算對象時繞過所有權。

不是一個問題 - 自動釋放池是線程局部。除了這種系統之外,我沒有看到一個問題(除非你依賴於競爭條件,這顯然是一個壞主意)。

+1

感謝賈斯汀。很好解釋。 – user2573923

3

autorelease仍然在ARC下使用。 ARC只是給你打電話,並且很聰明地將它短路。究竟如何工作的,我將在這裏的情況下複製博客文章永遠消失Here is a demonstration;所有應得的信貸給馬特加洛韋。

因此考慮下面的方法:

void foo() { 
    @autoreleasepool { 
     NSNumber *number = [NSNumber numberWithInt:0]; 
     NSLog(@"number = %p", number); 
    } 
} 

這完全是人爲的,當然,但它應該讓我們看到了什麼 回事。在非ARC地區,我們假設在numberWithInt中分配的號碼爲 ,並返回自動發佈。因此,當 自動釋放池下次耗盡時,它將被釋放。因此,讓我們看看 這是發生了什麼事情(像往常一樣,這是ARMv7的指令):

.globl _foo 
    .align 2 
    .code 16 
    .thumb_func  _foo 
_foo: 
    push {r4, r7, lr} 
    add  r7, sp, #4 
    blx  _objc_autoreleasePoolPush 
    movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
    movs r2, #0 
    movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
    mov  r4, r0 
    movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
LPC0_0: 
    add  r1, pc 
    movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
LPC0_1: 
    add  r0, pc 
    ldr  r1, [r1] 
    ldr  r0, [r0] 
    blx  _objc_msgSend 
    mov  r1, r0 
    movw r0, :lower16:(L__unnamed_cfstring_-(LPC0_2+4)) 
    movt r0, :upper16:(L__unnamed_cfstring_-(LPC0_2+4)) 
LPC0_2: 
    add  r0, pc 
    blx  _NSLog 
    mov  r0, r4 
    blx  _objc_autoreleasePoolPop 
    pop  {r4, r7, pc} 

嗯,是的。這正是發生的事情。我們可以看到撥打 的電話按一個自動釋放池,然後撥打numberWithInt:然後撥打 彈出一個自動釋放池。正是我們所期望的。現在,讓我們來看看 下ARC編譯完全相同的代碼:

.globl _foo 
    .align 2 
    .code 16 
    .thumb_func  _foo 
_foo: 
    push {r4, r5, r7, lr} 
    add  r7, sp, #8 
    blx  _objc_autoreleasePoolPush 
    movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
    movs r2, #0 
    movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC0_0+4)) 
    mov  r4, r0 
    movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
LPC0_0: 
    add  r1, pc 
    movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC0_1+4)) 
LPC0_1: 
    add  r0, pc 
    ldr  r1, [r1] 
    ldr  r0, [r0] 
    blx  _objc_msgSend 
    @ InlineAsm Start 
    mov  r7, r7   @ marker for objc_retainAutoreleaseReturnValue 
    @ InlineAsm End 
    blx  _objc_retainAutoreleasedReturnValue 
    mov  r5, r0 
    movw r0, :lower16:(L__unnamed_cfstring_-(LPC0_2+4)) 
    movt r0, :upper16:(L__unnamed_cfstring_-(LPC0_2+4)) 
    mov  r1, r5 
LPC0_2: 
    add  r0, pc 
    blx  _NSLog 
    mov  r0, r5 
    blx  _objc_release 
    mov  r0, r4 
    blx  _objc_autoreleasePoolPop 
    pop  {r4, r5, r7, pc} 

通知書objc_retainAutoreleasedReturnValue的電話和 objc_release。發生了什麼事有是ARC已經爲我們 ,它並不真正需要擔心的自動釋放池這項工作到位 確定的,因爲它可以簡單地告訴了自動釋放不發生 (與調用objc_retainAutoreleasedReturnValue),然後釋放 對象後來本身。這是可取的,因爲它意味着自動釋放邏輯不必發生。

注意,自動釋放池仍然需要推動和 殺出因爲ARC不知道發生了什麼事情在調用 numberWithInt:和NSLog的知道,如果對象將被放入池中 那裏。如果它確實知道他們沒有自動發佈任何東西,那麼它實際上可以擺脫推動和流行。雖然我不太確定這種 的語義如何工作,但也許這種 邏輯會在未來的版本中出現。

現在我們來考慮另一個例子,我們希望在自動釋放池塊範圍之外使用 數字。這應該 告訴我們爲什麼ARC是一個奇蹟般的工作。請看下面的代碼:

void bar() { 
    NSNumber *number; 
    @autoreleasepool { 
     number = [NSNumber numberWithInt:0]; 
     NSLog(@"number = %p", number); 
    } 
    NSLog(@"number = %p", number); 
} 

你可能會(正確地)認爲這將導致問題 即使它看起來完全無害的。這是一個問題,因爲 號碼將在自動釋放池塊內分配,當自動釋放池彈出時將釋放 ,但在釋放其 之後使用。呃哦!讓我們看看,如果我們是正確的通過編譯它 沒有ARC啓用:

.globl _bar 
    .align 2 
    .code 16 
    .thumb_func  _bar 
_bar: 
    push {r4, r5, r6, r7, lr} 
    add  r7, sp, #12 
    blx  _objc_autoreleasePoolPush 
    movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) 
    movs r2, #0 
    movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) 
    mov  r4, r0 
    movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) 
LPC1_0: 
    add  r1, pc 
    movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) 
LPC1_1: 
    add  r0, pc 
    ldr  r1, [r1] 
    ldr  r0, [r0] 
    blx  _objc_msgSend 
    movw r6, :lower16:(L__unnamed_cfstring_-(LPC1_2+4)) 
    movt r6, :upper16:(L__unnamed_cfstring_-(LPC1_2+4)) 
LPC1_2: 
    add  r6, pc 
    mov  r5, r0 
    mov  r1, r5 
    mov  r0, r6 
    blx  _NSLog 
    mov  r0, r4 
    blx  _objc_autoreleasePoolPop 
    mov  r0, r6 
    mov  r1, r5 
    blx  _NSLog 
    pop  {r4, r5, r6, r7, pc} 

顯然沒有來電保留,釋放或自動釋放,因爲我們所期待 ,因爲我們還沒有做出任何明確的,我們也不使用ARC。我們可以在 這裏看到,它的編譯完全和我們之前推測的 一樣。讓我們看看是什麼樣子時,ARC給了我們一個 援助之手:

爲ARC請掌聲
.globl _bar 
    .align 2 
    .code 16 
    .thumb_func  _bar 
_bar: 
    push {r4, r5, r6, r7, lr} 
    add  r7, sp, #12 
    blx  _objc_autoreleasePoolPush 
    movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) 
    movs r2, #0 
    movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC1_0+4)) 
    mov  r4, r0 
    movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) 
LPC1_0: 
    add  r1, pc 
    movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC1_1+4)) 
LPC1_1: 
    add  r0, pc 
    ldr  r1, [r1] 
    ldr  r0, [r0] 
    blx  _objc_msgSend 
    @ InlineAsm Start 
    mov  r7, r7   @ marker for objc_retainAutoreleaseReturnValue 
    @ InlineAsm End 
    blx  _objc_retainAutoreleasedReturnValue 
    movw r6, :lower16:(L__unnamed_cfstring_-(LPC1_2+4)) 
    movt r6, :upper16:(L__unnamed_cfstring_-(LPC1_2+4)) 
LPC1_2: 
    add  r6, pc 
    mov  r5, r0 
    mov  r1, r5 
    mov  r0, r6 
    blx  _NSLog 
    mov  r0, r4 
    blx  _objc_autoreleasePoolPop 
    mov  r0, r6 
    mov  r1, r5 
    blx  _NSLog 
    mov  r0, r5 
    blx  _objc_release 
    pop  {r4, r5, r6, r7, pc} 

回合!注意到我們使用的數字是 ,它使用的數字超出了autorelease池塊的範圍,所以 它保留了numberWithInt的返回值:就像之前的 一樣,但是這一次它將版本放置在條的末尾 函數,而不是在autorelease池被彈出之前。這將 我們節省一些代碼,我們可能有一個思想碰撞是 正確的,但實際上有一個微妙的內存管理錯誤。

+0

通過我的版權法律的理解,公平使用與歸屬沒有附帶任何「這麼多」預選賽。如果您認爲我的歸屬不夠清楚,請提供一個足夠您的例子,我將對其進行編輯。如果您認爲版權材料的公平使用確實有規定長度的限制,請聯繫這一事實的文件,所以我可以教育自己。 –

+0

是的,我在那裏看到「如果輔助用戶僅複製儘可能是必要的他或她的用途」。這裏的預期用途是全面回答這個問題。以上哪些部分顯然是不必要的?如果提問者同意,我肯定會刪除那部分。 –

+0

嘿。我只是通過他的網站通過電子郵件發送給他。所以我相信我們可以在Matt認爲必要的任何編輯將會讓你滿意的時候離開它,然後呢? –

1

然而,ARC能夠計算呼叫者的所有權和使用權後釋放 ,也就是說,它可以行爲就像++智能指針的溫度。 使用ARC,它可以擺脫autorelease,因爲autorelease是 非確定性的。

你是混亂的ARC與引用計數。 Objective-C一直依靠內存管理的引用計數。 ARC延續了這一傳統,只是省去了程序員手動插入適當的呼叫-retain-release-autorelease。在ARC下,編譯器會爲您插入這些調用,但引用計數機制與以往一樣保持不變。

ARC確實不是消除了自動釋放的需要,但它可能能夠避免在人類通常使用它的情況下。