祖父母、親、子の3つのオブジェクトがあるとします。祖父母は親を保持し、親は子を保持し、子は親を保持します。祖父母は親を解放します。
この場合はどうなりますか?
親または子への他の参照がない限り、それらは両方とも孤立します。しかし、親と子の間の保持サイクルにより、どちらも解放されず、メモリが無駄になります。
子供が親を保持することはありません。どちらかといえば、子への弱い参照を使用して、親への参照を維持します。
保持サイクルは、2つのオブジェクトが相互に参照を保持して保持されている場合の条件です。両方のオブジェクトが互いに保持しようとするため、保持サイクルが作成され、解放できなくなります。
ここで、「祖父母」は「親」を保持し、「親」は「子」を保持しますが、「子」は「親」を保持します。ここでは、親と子の間に保持サイクルが確立されます。祖父母を解放した後、親と子の両方が孤立しますが、子によって保持されているため、親の保持カウントがゼロにならず、メモリ管理の問題が発生します。
次の2つの解決策があります。
1)親への弱いポインターを使用します。つまり、子は保持されない親への弱い参照を使用する必要があります。
2)「クローズ」メソッドを使用して、保持サイクルを中断します。
http://www.cocoawithlove.com/2009/07/rules-to-avoid-retain-cycles.html
単純なケースでは、AがBを作成して保持する2つのオブジェクトAとBを検討します。Aが作成されると、Bが作成されます。 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への参照がないためです。 AまたはBがプロセッサを集中的に使用している場合、CPU時間を不要なオブジェクトにリークしている可能性もあります。
あなたの場合、Aは親であり、Bは子であり、作成されたAは祖父母です。
保持サイクルは、オブジェクトAがオブジェクトBを保持し、オブジェクトBがオブジェクトAを保持するときに発生するループです。その状況で、いずれかのオブジェクトがリリースされた場合:
したがって、これらの2つのオブジェクトは、すべてが正常に機能していれば割り当てを解除する必要がありますが、プログラムの存続期間中はメモリ内にたまるだけです。
祖父母が親を解放しても、子は親を保持しているため、親はまだ生きています。
祖父母:ジョン親:テッド子供:メアリー
これは、説明のために電話を使用した私の例です。
ジョンはテッドに電話し、メアリーと電話会議をしたいと考えています。
テッドはジョンに次のように語っています。「電話を切って、メアリーにダイヤルします」
テッドはジョンを保留にし、電話にすぐに応答するメアリーを呼び出します。
メアリーはテッドに次のように言います:「ジョンと私の電話を結合し、私が終わるまで私は電話を切らない」
テッドはしばらくジョンから返事をしなかったため、他のことをするために電話を残しました。
ジョンは、コールをテッドとメアリーとマージし、突然死にます。
メアリーはジョンへの回線に引っかかっていますが、ジョンが戻ってこないので電話を切ることはありません!
保持サイクルは、2つのオブジェクトが相互に参照を保持して保持される、両方のオブジェクトから保持サイクルを作成する保持する場合の条件です互いに、リリースすることを不可能にします。
例:人は部署に住んでおり、部署には人が1人います。
@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に減分され、ハングアップし続けます。
保持サイクルはデッドロック状態です。保持サイクルの実際の例:2つのオブジェクトが相互に参照を保持し、他のオブジェクトがリリースされない場合。
例:ラミーゲーム