保留周期:为什么这么糟糕?

Tha*_*nks 10 iphone cocoa-touch memory-management

有两个对象A和B. A创建B并保留它.B有一个指向A的实例变量,保留它.所以两者都保持着彼此.有人说,这种强大的联系不能再被打破.

但情况确实如此吗?

如果B将释放A,则A可以轻松释放B,因此B将被释放.一旦它的其他所有者(我想必须有人)释放它,它就会被解除分配.

或者此问题仅适用于A不创建B的情况,但只是通过将其保留在实例变量中来保存对它的强引用?我仍然不明白为什么这种联系不能再被打破.

Sco*_*ham 15

循环并不坏,但它们经常被避免,因为它们可以使它变得棘手,以确保您没有内存泄漏.特别是当对象被"引用计数"时会发生泄漏.在使用引用计数的语言或系统中,对象会跟踪指向它的引用数.每次删除引用时,计数都会下降,当计数变为零时,没有引用,因此可以删除该对象.

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

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

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

当您不再需要一组对象时,为了避免泄漏风险和正确打破周期的棘手工作,程序员通常会尝试避免循环.对于那些没有人理解整个系统的程序员而言,这对于大型项目来说变得更加重要.如果存在周期,程序员必须注意并花费很长时间来研究彼此的代码以避免周期.

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

  • Objective-C的垃圾收集器(启用时)也可以删除retain-loop组(几乎所有垃圾收集器都可以),但这与iPhone不相关,而不支持Objective-C垃圾收集. (2认同)

rin*_*ind 7

如果您了解保留周期,可以打破保留周期.通常它会导致讨厌的错误(内存泄漏).在你的例子中:

A* a = [[A alloc] initAndCreateB];
Run Code Online (Sandbox Code Playgroud)

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

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

[a release];
return 12;
Run Code Online (Sandbox Code Playgroud)

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