はあなたの最初の例を考えてみます(配列の+1
から0
へのカウントを保持を減らす)[arraytest release]
と呼ばれた後、オブジェクトがarraytest
で指されるので、最後NSLog
文は、非常に危険である
NSMutableArray *arraytest = [[NSMutableArray alloc] init];
// `arraytest` populated ...
NSLog(@"arraytest before:%@", arraytest);
[arraytest release];
NSLog(@"arraytest after:%@", arraytest); // DANGER: referencing dangling pointer!!!
はされているでしょう割り当てが解除され、arraytest
は、その解放されたメモリに対してdangling pointerになりました。割り当てが解除された後は、ポインタを決して参照しないでください。時にはあなたのように見えるかもしれませんが、安全ではないので、あなたのアプリは突然クラッシュすることがあります。 (あなたはゾンビを使用した場合は、しかし、それは安全に誤っこのダングリングポインタを使用するように試みのことを警告しているだろう。)
あなたの第二の例を検討します。この例では
NSMutableArray *arraytest = [[NSMutableArray alloc] init];
// `arraytest` populated ...
NSLog(@"arraytest before:%@",arraytest);
NSMutableArray *copyarray = [arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@", copyarray);
NSLog(@"arraytest after:%@", arraytest); // DANGER: referencing dangling pointer!!!
を、まだあなたは、あなたがそれをリリースした後、非常に危険なNSLog
のarraytest
を最後に持っていて、そのぶら下がっているポインタを使用すると簡単にクラッシュする可能性があります。だからあなたはそれを取り除きたいと思うでしょう。
これで、リークが発生しました。 arraytest
が最初に指したオブジェクトをリリースしたときに、copyarray
が指し示すオブジェクトを解放していない場合は、mutableCopy
の結果を返します。したがって、この新しいcopyarray
インスタンスにはリークが発生します。したがって、最初にarraytest
を作成したときに割り当てられた文字列は、リークされたcopyarray
によって参照され、リークされます。
このルーチンの最後に[copyarray release]
を追加した場合、リークしている配列と漏れている文字列の両方が解決されています。
今、唯一の最終インスツルメンツ画面のスナップショットに示されているあなたの第三の例、考えてみます。この最後の例で
NSMutableArray *arraytest = [[NSMutableArray alloc] init];
for (int i=0; i<100; i++) {
NSString *str = [NSString stringWithFormat:@"string:%d", i];
[arraytest addObject:str];
[str release]; // DANGER: released `str` whose ownership was never transferred to you!!!
}
NSLog(@"arraytest before:%@",arraytest);
NSMutableArray *copyarray=[arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@",copyarray);
NSLog(@"arraytest after:%@",arraytest); // DANGER: referencing dangling pointer!!!
を、私たちはあなただけに追加された文字列をoverreleasingことで、問題を配合しています配列。だから、(自動解放プールが排出されたときに効果的に保持カウントがゼロになります)自動解放オブジェクトを作成し、(+1
へのカウントを保持してその効果を上げる)の配列に追加して、str
をリリース(それはバック時に+0
に、カウントを保持しています削減プールの排水)。
現在、アレイは、自動解放プールが空になったときにリリースされる可能性があるオブジェクトを参照しているため、不安定な状況にあり、手間のかかるポインタの配列で終わってしまいます。さらに悪いことに、この配列が適切に解放された場合、それらの文字列のすべてが上書きされます。上記、第二の例で説明したように
とは、もちろん、あなたはまだ、配列の漏れを持っています。しかし、もしあなたがこの
copyarray
を適切にリリースしたならば、それらの文字列のすべてが過剰にリリースされます。
おそらく
この時点では言うまでもないが、このリークを解消する方法は、単にcopyarray
を解放することです:
NSMutableArray *arraytest = [[NSMutableArray alloc] init];
for (int i=0; i<100; i++) {
NSString *str = [NSString stringWithFormat:@"string:%d", i];
[arraytest addObject:str];
}
NSLog(@"arraytest before:%@", arraytest);
NSMutableArray *copyarray = [arraytest mutableCopy];
[arraytest release];
NSLog(@"copyarray:%@", copyarray);
[copyarray release];
これは、あなたがrelease
を呼び出すための責任がある、すなわちこと、Basic Memory Management Rulesを次のあなたがのおかげで所有しているオブジェクトはalloc
、new
、copy
、またはmutableCopy
)で始まるメソッドからそれらを受け取りました。
閉じ観測のカップル:
手動参照カウントを使用するつもりなら、私はあなたがXcodeのの静的アナライザを頻繁に利用することをお勧めしたいが(シフト + コマンド + B、またはXcodeの「Product」メニューの「Analyze」)。手動の参照カウントメモリの問題を特定することは驚くべきことです。インストゥルメントは便利ですが、上記の3番目の例で示したように、間違った結論に簡単に引き寄せることができます(例:「そう、すべての文字列を解放する必要があります)。スタティックアナライザは、これらの問題のいくつかをあなたに指摘していたでしょう。
ボトムラインは、常にあなたがさらに進む前に、静的アナライザからの健康のクリーン法案を持っていることを確認してください。インストゥルメントが問題の内容を正確に伝えることができた場合、その問題をリバースエンジニアリングすることは何の意味もありません。
私は特定のダングリングポインタは、あなたのアプリがクラッシュしなかったが、他がやったという事実から何らかの結論を描くない助言します。予期しないことだ。ゾンビを有効にした場合(一時的には、実稼働アプリケーションではなく、開発/テスト目的でのみ)、以前に割り当て解除されたオブジェクトを参照しようとする試みには注意が必要です。
私はあなたのテストでNSString
を使用していることに気付きます。NSString
には、非標準的な動作を引き起こす可能性のある内部メモリの最適化があることに注意してください。これらの種類の実験では、NSString
を使用することには注意が必要です。
間違ってはいけません:Basic Memory Management Rulesのすべてに従うと、NSString
は適切に動作します。しかし、意図的にメモリ管理ルールに従わなかったときにどのようなエラーやクラッシュが発生するのか調べる場合は、NSString
が誤解を招く可能性があることに注意してください。
言うまでもなく、ARCを使用すると、あなたの人生は大幅に簡素化されます。詳細は、Transitioning to ARC Release Notesを参照してください。