深入了解保留周期

假设我们有三个对象:祖父母,父母和孩子。 祖父母保留父母,父母保留孩子,孩子保留父母。 祖父母释放父母。

在这种情况下会发生什么?

除非另外提到父母或小孩,否则他们都会成为孤儿。 但父母之间的保留周期阻止了被释放,并成为浪费的记忆。

小孩不应该保留父母。 如果有的话,在孩子中使用一个弱引用来维护对父代的引用。

保留周期是条件当两个对象保持彼此的引用并被保留时,它会创build一个保留周期,因为两个对象都试图保留对方,从而无法释放。

在这里,“祖父母”保留“父母”和“父母”保留“孩子”作为“孩子”保留“父母”的地方。这里在父母和孩子之间build立保留周期。 在释放祖父母之后,父母和子女都成为孤儿,但父母的保留数量不会为零,因为它被孩子保留,因此引起memory management问题。

有两种可能的解决scheme:

1)使用弱指针到父,即一个孩子应该使用弱引用到父,这是不被保留。

2)使用“closures”方法打破保留周期。

http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html

在一个简单的情况下,考虑两个对象A和B,其中A创build并保留B.当A创build时,它创buildB.当创buildA的人最终释放它时,A的保留计数下降到零,并且被解除分配。 如果A的dealloc方法调用B上的释放,则B的保留计数也下降到零,并且它也被释放。 [这个假设没有人保留A或B,因为我保持简单。]

但是,如果B需要一个参考,并保留A,那会发生什么? 谁创造了A可能会释放它。 但是由于B也保留了A,所以A的保留数不会为零。 同样,由于A保留B,所以B的保留数也不会为零。 也不会被释放。 即使B在自己的dealloc中调用A的释放方法也没关系,因为这个方法永远不会被调用。

在这一点上,你有一个内存泄漏,因为你没有任何引用A或B,即使他们都存在。 如果A或B正在做任何处理器密集的事情,那么你可能也会泄漏CPU时间到不需要的对象。

在你的情况下,A是父母,B是孩子,而创造A的人是祖父母。

保持周期是当对象A保持对象B并且对象B保持对象A时发生的循环。在这种情况下,如果任一对象被释放:

  • 对象A不会被释放,因为对象B持有对它的引用(保留计数> 0)。
  • 只要对象A有引用,对象B就不会被释放(保留计数> 0)。
  • 但是对象A永远不会被释放,因为对象B持有对它的引用(保留计数> 0)。
  • 直到无限

因此,这两个对象只会在程序的整个生命周期中回忆起来,尽pipe如果一切工作正常的话,它们都应该被释放。

当祖父母释放父母时,父母仍然活着,因为孩子保留父母。

保留周期两个对象彼此保持引用并被保留的条件它创build了一个保留周期,因为两个对象都试图保留对方,从而无法释放。


例如:一个人住在一个​​部门,一个部门有一个人。

@class Department; @interface Person:NSObject @property (strong,nonatomic)Department * department; @end @implementation Person -(void)dealloc{ NSLog(@"dealloc person"); } @end @interface Department: NSObject @property (strong,nonatomic)Person * person; @end @implementation Department -(void)dealloc{ NSLog(@"dealloc Department"); } @end 

然后像这样调用它:

 - (void)viewDidLoad { [super viewDidLoad]; Person * person = [[Person alloc] init]; Department * department = [[Department alloc] init]; person.department = department; department.person = person; } 

你不会看到dealloc日志,这是保留圈。

由于P对象的retainCount为1,当它释放时,其retainCount变为0,并调用其dealloc方法; 这又调用C对象的释放,其保留计数也变为0; 并调用其dealloc方法。

对象P和C都将被释放。

当C对象的dealloc方法被调用时,依次调用GP对象的释放,但是由于GP的保留计数为2,保留计数递减为1,并继续挂起。