iOS-深入了解保留周期

可以说我们有三个对象:祖父母,父母和孩子。 祖父母保留父母,父母保留子女,孩子保留父母。 祖父母释放父母。

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

9个解决方案
71 votes

除非另有提及父母或子女,否则他们都会成为孤儿。 但是,父级和子级之间的保留周期会阻止两者之一释放,并且它们会浪费内存。

孩子永远不要保留父母。 如果有的话,请在子级中使用弱引用来维护对父级的引用。

rmaddy answered 2020-01-14T07:45:16Z
26 votes

保留周期为条件当2个对象相互引用并被保留时,由于两个对象都试图相互保留,因此将创建一个保留周期,从而无法释放。

在这里,“祖父母”保留“父母”,“父母”保留“孩子”,而“孩子”保留“父母”。在这里,在父母与孩子之间建立了保留周期。 释放祖父母后,父母和孩子都成为孤儿,但是父母的保留计数不会为零,因为它被孩子保留,因此会引起内存管理问题。

有两种可能的解决方案:

1)使用指向父级的弱指针,即子级应该使用对父级的弱引用,但不保留。

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

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

Aritra Das answered 2020-01-14T07:45:59Z
10 votes

在一个简单的情况下,考虑两个对象A和B,其中A创建并保留B。创建A时,它创建B。当创建A的任何人最终释放它时,A的保留数都降为零,并被释放。 如果A的dealloc方法调用B的release,则B的保留计数也将降为零,并且也会被释放。 [这假设没有其他人保留A或B,因为我保持简单。

但是,如果B需要引用A并保留A会发生什么呢? 创建A的人可能会释放它。 但是由于B也保留了A,因此A的保留数不会为零。 同样,由于A保留了B,因此B的保留数也不会为零。 两者都不会被释放。 即使B在自己的dealloc中调用A的release方法也没关系,因为永远不会调用该方法。

此时,您将发生内存泄漏,因为即使它们仍然存在,也没有对A或B的引用。 如果A或B正在做任何占用大量处理器资源的事情,那么您可能还会将CPU时间浪费在不需要的对象上。

在您的情况下,A是父母,B是孩子,创建者A是祖父母。

RMDeveloper answered 2020-01-14T07:46:34Z
5 votes

保留周期是当对象A保留对象B而对象B保留对象A时发生的循环。在这种情况下,如果释放了任何一个对象,则:

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

因此,即使在一切正常的情况下,这两个对象也应该在程序的整个生命周期中徘徊,即使它们在一切正常的情况下也应该被释放。

Aamir answered 2020-01-14T07:47:16Z
4 votes

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

Danyun Liu answered 2020-01-14T07:47:36Z
1 votes

保留周期是两个对象相互引用并保留时的情况,由于两个对象都试图相互保留,因此无法释放,因此创建了一个保留周期。


示例:一个人住在一个部门中,一个部门有一个人。

@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 log,这是保留圈。

delarcomarta answered 2020-01-14T07:48:10Z
1 votes

祖父母:约翰父母:特德孩子:玛丽

这是我的示例,其中使用电话进行说明:

  • 约翰给特德打了电话,想和玛丽进行电话会议。

  • 泰德对约翰说:“挂线,我要拨玛丽的电话”

  • 特德(Ted)保留约翰(John)的电话,并致电玛丽(Mary),后者立即接听电话。

  • 玛丽对特德说:“与约翰合并,直到我通过,我才挂断电话”

  • 泰德(Ted)很久没收到约翰的来信了,他留下了做其他事情的电话。

  • 约翰去与特德和玛丽合并电话,然后突然去世。

  • 玛丽被困在去约翰的电话上,但是永远不会挂断电话,因为约翰不会回来!

paul_f answered 2020-01-14T07:49:06Z
0 votes

由于P对象的retainCount为1,因此释放它时,其retainCount变为0,并调用其dealloc方法; 依次调用C对象的release,其保留计数也为0; 并调用其dealloc方法。

对象P和C都将被释放。

当调用C对象的dealloc方法时,又调用了GP对象的release,但是由于GP的保留计数为2,因此保留计数递减为1,并继续徘徊。

Shalab answered 2020-01-14T07:49:35Z
0 votes

保持周期是一个死锁条件。保留周期的实际示例:如果两个对象彼此保持引用,并且没有其他对象被释放。

示例:Rummy游戏

Saurabh Sharma answered 2020-01-14T07:50:00Z
translate from https://stackoverflow.com:/questions/19892245/understanding-retain-cycle-in-depth