Kud*_*oCC 3 objective-c ios automatic-ref-counting
我有一个方法createATestObject.正如其名称所示,它创建一个对象并将其返回.代码很简单,它在ARC下.
- (TestObj *)createATestObj
{
return [[TestObj alloc] init] ;
}
Run Code Online (Sandbox Code Playgroud)
我汇编文件并获得下面的汇编代码.
Lfunc_begin4:
.cfi_startproc
@ BB#0:
push {r7, lr}
mov r7, sp
sub sp, #8
@DEBUG_VALUE: -[ViewController createATestObj]:self <- undef
@DEBUG_VALUE: -[ViewController createATestObj]:_cmd <- undef
str r0, [sp, #4]
str r1, [sp]
movw r0, :lower16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC4_0+4))
movt r0, :upper16:(L_OBJC_CLASSLIST_REFERENCES_$_-(LPC4_0+4))
LPC4_0:
add r0, pc
ldr r0, [r0]
movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_10-(LPC4_1+4))
movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_10-(LPC4_1+4))
LPC4_1:
add r1, pc
ldr r1, [r1]
blx _objc_msgSend
movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_-(LPC4_2+4))
movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_-(LPC4_2+4))
LPC4_2:
add r1, pc
ldr r1, [r1]
blx _objc_msgSend
add sp, #8
pop.w {r7, lr}
b.w _objc_autoreleaseReturnValue
Ltmp13:
Lfunc_end4:
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
我注意到了这个函数_objc_autoreleaseReturnValue并从这里获得了它的参考.但我不知道这意味着什么.任何人都可以详细说明吗?非常感谢.
id objc_autoreleaseReturnValue(id value);
前提条件:value为null或指向有效对象的指针.
如果value为null,则此调用无效.否则,它会尽最大努力将对象的保留计数的所有权移交给对封闭调用帧中的同一对象的objc_retainAutoreleasedReturnValue调用.如果不可能,则如上所述自动释放对象.
始终返回值.
首先感谢@Darren,感谢您的链接.
我在链接中引用了一些段落.
如果调用者和被调用者都是ARC,ARC有一个技巧可以将返回的对象保留在自动释放池之外.
但是这有什么作用呢?ARC的一个特性是旧的ARC编译代码(MRC代码)可以调用ARC代码,反之亦然.但是,如果ARC代码没有将返回的对象放入MRC代码所期望的自动释放池中,那么该对象就会泄漏.
因此,ARC-ified clang代码在返回对象时会发出此函数调用:objc_autoreleaseReturnValue(id).
如果你看一下objc_autoreleaseReturnValue的实现,它会调用callerAcceptsFastAutorelease().即使您没有阅读x86_64或ARM程序集,代码的注释也是直截了当的:
/*
Fast handling of returned autoreleased values.
The caller and callee cooperate to keep the returned object
out of the autorelease pool.
Caller:
ret = callee();
objc_retainAutoreleasedReturnValue(ret);
// use ret here
Callee:
// compute ret
[ret retain];
return objc_autoreleaseReturnValue(ret);
objc_autoreleaseReturnValue() examines the caller's instructions following
the return. If the caller's instructions immediately call
objc_autoreleaseReturnValue, then the callee omits the -autorelease and saves
the result in thread-local storage. If the caller does not look like it
cooperates, then the callee calls -autorelease as usual.
objc_autoreleaseReturnValue checks if the returned value is the same as the
one in thread-local storage. If it is, the value is used directly. If not,
the value is assumed to be truly autoreleased and is retained again. In
either case, the caller now has a retained reference to the value.
Tagged pointer objects do participate in the fast autorelease scheme,
because it saves message sends. They are not entered in the autorelease
pool in the slow case.
*/
Run Code Online (Sandbox Code Playgroud)
来自我的东西
我们来看看源代码了objc_autoreleaseReturnValue.
id
objc_autoreleaseReturnValue(id obj)
{
#if SUPPORT_RETURN_AUTORELEASE
assert(tls_get_direct(AUTORELEASE_POOL_RECLAIM_KEY) == NULL);
if (callerAcceptsFastAutorelease(__builtin_return_address(0))) {
tls_set_direct(AUTORELEASE_POOL_RECLAIM_KEY, obj);
return obj;
}
#endif
return objc_autorelease(obj);
}
Run Code Online (Sandbox Code Playgroud)
__builtin_return_address(0) 返回当前函数的返回地址,然后让我们看一下callerAcceptsFastAutoreleasearm版本的实现:
static bool callerAcceptsFastAutorelease(const void *ra)
{
// if the low bit is set, we're returning to thumb mode
if ((uintptr_t)ra & 1) {
// 3f 46 mov r7, r7
// we mask off the low bit via subtraction
if (*(uint16_t *)((uint8_t *)ra - 1) == 0x463f) {
return true;
}
} else {
// 07 70 a0 e1 mov r7, r7
if (*(uint32_t *)ra == 0xe1a07007) {
return true;
}
}
return false;
}
Run Code Online (Sandbox Code Playgroud)
在该方法中,它查找作为mov r7, r7标记的指令objc_retainAutoreleaseReturnValue,如果找到,则返回方法true,因此被调用者将省略自动释放.
你可以看到testFun1我的情况下调用者的汇编代码.
- (void)testFun1:(ViewController *)vc
{
[vc createATestObj] ;
}
Run Code Online (Sandbox Code Playgroud)
下面是汇编代码,你可以找到"mov r7,r7 @ marker for objc_retainAutoreleaseReturnValue"这一行
.cfi_startproc
@ BB#0:
push {r7, lr}
mov r7, sp
sub sp, #16
add r3, sp, #4
movw r9, #0
movt r9, #0
str r0, [sp, #12]
str r1, [sp, #8]
str.w r9, [sp, #4]
mov r0, r3
mov r1, r2
bl _objc_storeStrong
movw r0, :lower16:(L_objc_msgSend$non_lazy_ptr-(LPC5_0+4))
movt r0, :upper16:(L_objc_msgSend$non_lazy_ptr-(LPC5_0+4))
LPC5_0:
add r0, pc
ldr r0, [r0]
movw r1, :lower16:(L_OBJC_SELECTOR_REFERENCES_12-(LPC5_1+4))
movt r1, :upper16:(L_OBJC_SELECTOR_REFERENCES_12-(LPC5_1+4))
LPC5_1:
add r1, pc
Ltmp14:
ldr r2, [sp, #4]
ldr r1, [r1]
str r0, [sp] @ 4-byte Spill
mov r0, r2
ldr r2, [sp] @ 4-byte Reload
blx r2
@ InlineAsm Start
mov r7, r7 @ marker for objc_retainAutoreleaseReturnValue
.code 16
@ InlineAsm End
bl _objc_retainAutoreleasedReturnValue
bl _objc_release
movs r1, #0
movt r1, #0
add r0, sp, #4
bl _objc_storeStrong
add sp, #16
pop {r7, pc}
Ltmp15:
Lfunc_end5:
.cfi_endproc
Run Code Online (Sandbox Code Playgroud)
更新:
我认为苹果实施的评论中存在一些错误.
正确的评论应该是这样的:
/*
Fast handling of returned autoreleased values.
The caller and callee cooperate to keep the returned object
out of the autorelease pool.
Caller:
ret = callee();
objc_retainAutoreleasedReturnValue(ret);
// use ret here
Callee:
// compute ret
[ret retain];
return objc_autoreleaseReturnValue(ret);
objc_autoreleaseReturnValue() examines the caller's instructions following
the return. If the caller's instructions immediately call
objc_retainAutoreleasedReturnValue, then the callee omits the -autorelease and saves
the result in thread-local storage. If the caller does not look like it
cooperates, then the callee calls -autorelease as usual.
objc_retainAutoreleasedReturnValue checks if the returned value is the same as the
one in thread-local storage. If it is, the value is used directly. If not,
the value is assumed to be truly autoreleased and is retained again. In
either case, the caller now has a retained reference to the value.
Tagged pointer objects do participate in the fast autorelease scheme,
because it saves message sends. They are not entered in the autorelease
pool in the slow case.
*/
Run Code Online (Sandbox Code Playgroud)
如果你不同意我,请给我评论.谢谢!