objc_autoreleaseReturnValue和objc_retainAutoreleasedReturnValue函数对ARC优化

本文探讨了在Objective-C的Automatic Reference Counting (ARC)环境下,objc_autoreleaseReturnValue和objc_retainAutoreleasedReturnValue如何优化内存管理。当一个方法返回的对象被直接传递给objc_retainAutoreleasedReturnValue时,可以避免将对象放入自动释放池,从而提高性能。这一过程涉及到TLS(Thread Local Storage)技术,以实现线程安全且高效的内存管理。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

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函数。

评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值