为啥 __weak 变量未在自动释放池中注册?

Posted

技术标签:

【中文标题】为啥 __weak 变量未在自动释放池中注册?【英文标题】:Why __weak variable not registered in autorelease pool?为什么 __weak 变量未在自动释放池中注册? 【发布时间】:2017-11-20 09:32:27 【问题描述】:
id obj = [[NSObject alloc] init];
@autoreleasepool
    id __weak weakObj = obj;
    _objc_autoreleasePoolPrint();
    NSLog(@"%@",[weakObj class]);
    _objc_autoreleasePoolPrint();

运行上面的代码后,我在打印池时得到了意想不到的结果:

objc[22671]: [0x7ff544817858]  ################  POOL 0x7ff544817858
objc[22671]: ##############

我找不到在autoreleasepool 中注册的对象。为什么?

【问题讨论】:

weakObj 只是对obj 的引用,obj 是在自动释放池之外分配的 @Paulw11 感谢您的关注!我将obj分配在自动释放池中。但我得到了相同的结果。 【参考方案1】:

我认为您误解了自动释放池是什么。它是一个对象集合,当池耗尽时(最常见于事件循环结束时)将收到release 消息。它不是将“通过某种方式自动释放”的对象列表。 特别是此自动释放池将向对象发送release 消息(并且在任何给定时间可能有多个池)。

它与weak 毫无关系。 “弱”是变量(指针)的一个属性。 “自动释放”是发生在对象上的事情。对象可能会被多次自动释放(这是正常的)。

在手动内存管理中,这通常通过向对象发送-autorelease 来完成。这意味着“现在不要释放它;我仍然需要它,但是当当前的自动释放池耗尽时,释放它。”请注意,这并不意味着“摧毁它”。它只是意味着“将保留计数减少一”。这就是你所说的“我只关心这个对象直到事件循环结束”(这是一个非常非常普遍的说法)。

在 ARC 中,您不能直接调用 -autorelease,但 ARC 在某些情况下仍会使用自动释放池。一种非常常见的方法是在返回之前调用objc_autoreleaseReturnValue()。 (这不是您直接调用的东西。它是 ARC 在需要时自动注入的东西。)在某些情况下,objc_autoreleaseReturnValue() 仍然可能实际上将对象放在自动释放池中。编译器足够聪明,可以检测到许多可以避免池并提高性能的情况。在其他情况下,ARC 可能会注入自动释放,并且这些情况也有可能绕过池的优化。

请注意,一般情况下,您的应用不应该依赖此功能。 _objc_autoreleasePoolPrint() 是 Apple 内部函数,用于低级调试。某些东西是否在自动释放池中很大程度上取决于 ARC 实现细节和当前的编译器优化。

【讨论】:

【参考方案2】:

obj 永远不会自动释放,因此它不会放置在自动释放池中。如果你想自动释放obj,你必须调用-autorelease,例如

@autoreleasepool 
    id obj = [[[NSObject alloc] init] autorelease];
    // ...

请注意,-autorelease 在 ARC 代码中不可用。

【讨论】:

【参考方案3】:

我从这个link 得到答案。

Apple LLVM 8.0.0 版(clang-800.0.42.1)的__weak 新实现不会延迟发布到autoreleasepool,而是直接使用objc_release。

【讨论】:

以上是关于为啥 __weak 变量未在自动释放池中注册?的主要内容,如果未能解决你的问题,请参考以下文章

iOS自动释放池_原理_如何工作

iOS自动释放池_原理_如何工作

oc中 关于weak的粗浅理解

iOS-strong,copy,weak,assign等修饰符作用

为啥这段代码调用自动释放池?

何时使用自动释放变量? [复制]