因此考慮下面的方法:
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池被彈出之前。這將 我們節省一些代碼,我們可能有一個思想碰撞是 正確的,但實際上有一個微妙的內存管理錯誤。
自動釋放是不是在所有非確定性。池在運行循環的每次旋轉的底部向每個包含的對象發送'release'。 –
@JoshCaswell我在autorelease相關代碼中看到一些subtl錯誤。當代碼調用一個對象時,它實際上是「釋放」,但釋放是在運行循環的每次旋轉的底部完成的。當代碼遷移到ACR時,它崩潰。原因是ARC縮短了物體的壽命。 – user2573923
@ user2573923它是這樣做的,但除非使用'weak'引用,否則應該無關緊要,在使用它們之前,應始終在本地將其轉換爲'strong'。 –