保留周期:为啥这是一件坏事?

Posted

技术标签:

【中文标题】保留周期:为啥这是一件坏事?【英文标题】:Retain Cycles: Why is that such a bad thing?保留周期:为什么这是一件坏事? 【发布时间】:2010-10-21 22:29:10 【问题描述】:

有两个对象 A 和 B。A 创建 B 并保留它。 B 有一个指向 A 的实例变量,并保留它。所以双方互相挽留。有人说,这种牢固的联系再也不能断了。

但真的是这样吗?

如果 B 释放 A,那么 A 可以轻松释放 B,因此 B 将被释放。 A 将在它的其他所有者(我猜肯定有人)释放它后立即被释放。

或者这个问题是否只适用于 A 不创建 B,而只是通过将它保留在实例变量中来保持对它的强引用的情况?我仍然不明白为什么不能再次断开连接。

【问题讨论】:

【参考方案1】:

循环还不错,但通常会避免使用循环,因为它们会使确保您没有内存泄漏变得很棘手。尤其是当对象被“引用计数”时,就会发生泄漏。在使用引用计数的语言或系统中,对象会跟踪指向它的引用的数量。每次删除引用时,计数会下降,当计数为零时,没有引用,因此可以删除对象。

这通常会自行处理,无需任何仔细考虑即可正常工作。如果你有一组没有循环的对象并且你删除了对根对象的引用,那么它将被删除,这意味着它对它拥有的对象的引用将被删除,被引用的对象将有它们的引用计数归零。它们将被删除,级联将导致所有对象被删除。

但是......如果你有一个循环,这个级联就不起作用。您可能有一组对象并且您不再需要它们,因此您删除了对这些对象的唯一引用,但是因为存在一个循环对象相互引用。这意味着它们的引用计数永远不会归零,也不会被删除。这是内存泄漏。

显然,您可以在放弃对不再需要的一组对象的引用之前进行一些仔细的管理并打破循环。但是……正如我刚才所说,这需要仔细管理。很容易出错。这是发生内存泄漏的主要原因之一。

当您不再需要一组对象时,为了避免泄漏风险和正确打破循环的棘手工作,程序员通常会尽量避免循环。在没有人了解整个系统的许多程序员的大型项目中,这一点变得更加重要。如果存在循环,程序员将不得不小心并花很长时间研究彼此的代码以避免循环。

一些具有垃圾收集器的语言(例如 C#)可以删除不再需要的一组对象,即使该组包含循环。

【讨论】:

Objective-C 的垃圾收集器(启用时)也可以删除保留循环组(几乎所有垃圾收集器都可以),但这与不支持 Objective-C 垃圾收集的 iPhone 无关。 【参考方案2】:

如果您知道,可以打破保留周期。通常它会导致讨厌的错误(内存泄漏)。在您的示例中:

A* a = [[A alloc] initAndCreateB];

现在,一个未命名的 B 实例(由 A 创建)的保留计数为 1。由于我们持有对 A 的引用,而匿名 B 实例持有对 A 的强引用,因此 A 的保留计数为 2。

比方说,我们用 A 完成了:

[a release];
return 12;

现在,A 的保留计数为 1。它不会被释放,它的内存丢失了。这就是保留周期不好的原因。

【讨论】:

谢谢。据我了解,如果有两个不同的对象,它看起来并不像。 A 必须是 B 的超类,这样 B 的数据结构才能适合 A。但是这样做之后,a 不就是匿名 B 吗?我可能错了。来晚了;) A 不必是 B 的超类。它只是有一个指向 B 实例的 ivar。 B 是一个单独的对象。想想你每天看到的类:你可能有一个 NSArray、NSString 和一个 NSDate 作为实例变量。这些是您的自定义类的 not 子类。它们是您使用的独立类。【参考方案3】:

打破保留循环的方法是有一个单独的“关闭”方法。

A retains B
B retains A

完成后,在 A 释放 B 的 A 上调用一个方法(我称之为“close”)。然后您可以释放 A,整个循环将释放(假设其他地方没有保留) .

【讨论】:

【参考方案4】:

问题是这样的:A指向并保留B,B指向并保留A。当没有其他对A或B的引用时,将无法释放它们,因为您的应用程序没有那时对他们的任何引用。这称为引用循环,它是任何引用计数系统中常见的一种内存泄漏。大多数高级语言解决这个问题的方法是使用垃圾收集而不是引用计数。

【讨论】:

谢谢。但是为什么不应该提到 A 或 B 呢?在哪种情况下,我的应用程序没有引用它们的两个对象? 如果您确实有其他对 A 或 B 的引用,则没有问题。只有当您丢失这些引用(例如它们超出范围时)才是问题。

以上是关于保留周期:为啥这是一件坏事?的主要内容,如果未能解决你的问题,请参考以下文章

为啥在 ARC 中发送消息会导致保留周期警告,但属性集不会?

MKPlacemark() 创建保留周期

这会导致保留周期吗

iOS - 弱变量仍然会导致保留周期?

嵌套函数在 gcc 中是一件坏事吗? [关闭]

在此块中强烈捕获自我可能会导致保留周期