ARC对注册autoreleasepool优化
在ARC下
Person.m
+ (instancetype)myPerson {
Person *temp = [[Person alloc] init];
return temp;
}
main.m
Person *person = [Person myPerson];
NSArray *array = [[NSArray alloc] initWithObjects:person, nil];
NSLog(@"123");
非alloc/copy/mutableCopy/new开头的方法,返回的对象加入到自动释放池中,在《objective-c高级编程》中说返回注册到autoreleasepool中的对象的方法使用了objc_autoreleseReturnValue函数返回注册到autorelease中的对象。它会检查使用该函数的方法或函数调用方执行命令列表,如果紧接着调用了方法或函数后紧接着调用objc_retainAutoreleasedReturnValue()函数,那么就不将返回的对象注册到autoreleasePool中,而是直接传递到方法或函数的调用方,省略注册到释放池的过程。
在 Person *person = [Person myPerson];初始化打了断点,会调用objc_autoreleaseReturnValue
在myPerson打断点:
如果正常调用[[Person alloc] init]则不会出现这俩个函数。
源码
// Prepare a value at +1 for return through a +0 autoreleasing convention.
id
objc_autoreleaseReturnValue(id obj)
{
if (prepareOptimizedReturn(ReturnAtPlus1)) return obj;
return objc_autorelease(obj);
}
这里的obj_autorelease是真正的autorelease方法,上面if中的条件是优化autorelease的方法
// Try to prepare for optimized return with the given disposition (+0 or +1).
// Returns true if the optimized path is successful.
// Otherwise the return value must be retained and/or autoreleased as usual.
static ALWAYS_INLINE bool
prepareOptimizedReturn(ReturnDisposition disposition)
{
ASSERT(getReturnDisposition() == ReturnAtPlus0);
if (callerAcceptsOptimizedReturn(__builtin_return_address(0))) {
if (disposition) setReturnDisposition(disposition);
return true;
}
return false;
}
这里的ReturnAtPlus0是一个枚举
enum ReturnDisposition : bool {
ReturnAtPlus0 = false, ReturnAtPlus1 = true
};
static ALWAYS_INLINE ReturnDisposition
getReturnDisposition()
{
return (ReturnDisposition)(uintptr_t)tls_get_direct(RETURN_DISPOSITION_KEY);
}
static ALWAYS_INLINE void
setReturnDisposition(ReturnDisposition disposition)
{
tls_set_direct(RETURN_DISPOSITION_KEY, (void*)(uintptr_t)disposition);
}
看到最终是使用tls_get_direct(RETURN_DISPOSITION_KEY)取的 TLS(Thread Local Storage)里的值,取了后还把这个值变为true。
看看objc_retainAutoreleasedReturnValue
id
objc_retainAutoreleasedReturnValue(id obj)
{
if (acceptOptimizedReturn() == ReturnAtPlus1) return obj;
return objc_retain(obj);
}
static ALWAYS_INLINE ReturnDisposition
acceptOptimizedReturn()
{
ReturnDisposition disposition = getReturnDisposition();
setReturnDisposition(ReturnAtPlus0); // reset to the unoptimized state
return disposition;
}
直接给这个值设置了标记值为false,可以看到注释的意思是重置了标志状态。
省略了retain 和autorlease俩次方法调用。
tls
线程局部存储,为了省去繁琐的加锁过程,这里使用的tls线程局部存储技术,它是一个跨函数的线程全局变量。
tls的数据结构是一个进程级的全局数组,存放着tls的键值信息
数组的每个元素都是一个包含两个字段的结构,第一个字段标记该数组元素是否在用,第二个字段用于存放针对此键、线程局部存储变的解构函数的一个副本,即destructor函数。