NSAutoreleasePool自動解放プールはどのように機能しますか?


95

私が理解しているように、allocnew、またはcopyで作成されたものはすべて手動で解放する必要があります。例えば:

int main(void) {
    NSString *string;
    string = [[NSString alloc] init];
    /* use the string */
    [string release];
}

しかし、私の質問は、これは同じように有効ではないでしょうか?:

int main(void) {
    NSAutoreleasePool *pool;
    pool = [[NSAutoreleasePool alloc] init];
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
    [pool drain];
}

回答:


68

はい、2番目のコードスニペットは完全に有効です。

-autoreleaseがオブジェクトに送信されるたびに、最も内側の自動解放プールに追加されます。プールが空になると、プール内のすべてのオブジェクトに-releaseが送信されます。

自動解放プールは単に、「後で」送信するまで送信を延期できる便利なものです。その「後で」はいくつかの場所で発生する可能性がありますが、Cocoa GUIアプリで最も一般的なのは、現在の実行ループサイクルの終わりです。


5
ループがない場合、現在の実行ループサイクルの終わりはどこですか?
感謝

24
「最も外側」が「最も内側」であるべきではありませんか?
マイクウェラー

an objectする必要がありますan object that is a subclass of NSObject or NSProxy and doesn't override -autorelease

1
編集:最も外側から最も内側に変更されました。
chakrit

1
重要:自動参照カウント(ARC)を使用する場合、自動解放プールを直接使用することはできません。代わりに、@ autoreleasepoolブロックを使用します。developer.apple.com/library/mac/#documentation/Cocoa/Reference/…
Md Mahbubur Ra​​hman

37

NSAutoreleasePool:ドレインとリリース

の機能drainrelease混乱を引き起こしているように見えるため、ここで明確にする価値があるかもしれません(ただし、ドキュメントで説明されていますが ...)。

厳密に言えば、全体像の観点からdrainは次と同等ではありませんrelease

参照カウント環境でdrainは、はと同じ操作を実行するreleaseので、2つはその意味で同等です。強調するために、この手段は、あなたがないではない、あなたが使用している場合は、プールをリークするdrainのではなくrelease

ガベージコレクションされた環境でreleaseは、何も行われません。したがって、効果はありません。 drain一方、「必要に応じて収集する」というコレクターへのヒ​​ントが含まれています。したがって、ガベージコレクションされた環境では、を使用drainすると、システムがコレクションスイープのバランスを取るのに役立ちます。


4
を「リーク」することは基本的に不可能NSAutoreleasePoolです。これは、プールがスタックのように動作するためです。プールをインスタンス化すると、そのプールがそのスレッド自動解放プールスタックの一番上にプッシュされます。 -releaseそのプールをスタックおよびその上にプッシュされたプールからポップしますが、何らかの理由でポップされませんでした。
johne 2009

7
これは私が書いたものとどのように関連していますか?
mmalc 2010年

2
私は彼が大胆なANDに時間をかけた方法が好きです。スナップ!
ビリーグレイ、

17

すでに指摘したように、2番目のコードスニペットは正しいです。

すべての環境(参照カウント、GC、ARC)で機能し、ドレイン/リリースの混乱を回避する自動リリースプールのより簡潔な方法を提案したいと思います。

int main(void) {
  @autoreleasepool {
    NSString *string;
    string = [[[NSString alloc] init] autorelease];
    /* use the string */
  }
}

上記の例では、@ autoreleasepoolブロックに注意してください。これはここに文書化されています


2
ARCでは自動解放は許可されていないことに注意してください。
dmirkitanov

1
明確にするために、@autoreleasepoolARCでブロックを使用する必要があります。
Simon

7

いや、違うよ。ドキュメントには、GC以外では-drainが-releaseと同等であることを明記しており、NSAutoreleasePoolはリークされません。


その場合、Xcodeが-drainを使用してコードを生成するのはなぜかと思いました。Xcodeによって生成されたコードに基づく-releaseと同等だと思ったので、-drainを使用しました。
James Sumners、

1
それは根本的に不可能であると「リーク」A NSAutoreleasePooldeveloper.apple.com/mac/library/documentation/Cocoa/Conceptual/...
ヨーネ


0

オブジェクトにリリースする代わりに自動リリースを送信すると、少なくともプール自体が排出されるまで、そのオブジェクトの寿命が延長されます(オブジェクトが後で保持される場合は長くなる可能性があります)。オブジェクトは同じプールに数回入れることができます。その場合、オブジェクトはプールに入れられるたびに解放メッセージを受け取ります。


-2

はいといいえ。文字列メモリを解放することになりますが、ガベージコレクションされた(メモリ管理されていない)環境でこれを実行した場合、解放ではなくドレインを使用してNSAutoreleasePoolオブジェクトをメモリに「リーク」します。この「リーク」は、NSAutoreleasePoolのインスタンスを、GCの下で強力なポインターを持たない他のオブジェクトと同様に「到達不能」にするだけであり、オブジェクトは、次にGCが実行されるときにクリーンアップされます-drain

ドレイン

ガベージコレクションされた環境では、最後のコレクション以降に割り当てられたメモリが現在のしきい値より大きい場合、ガベージコレクションをトリガーします。それ以外の場合はリリースとして動作します。...ガベージコレクションされた環境では、このメソッドは最終的にを呼び出しますobjc_collect_if_needed

それ以外の場合は、-releaseGC以外での動作に似ています(はい)。他の人が述べたように、-releaseGCの下では何もしないので、プールがGCの下で適切に機能することを確認する唯一の方法はを介して行われ-drain-drain非GCの下でも非GCの下とまったく同じように-release機能し、間違いなくその機能をより明確に通信します。上手。

「new、alloc、initで呼び出されたもの」には「init」を含めないでください(ただし「copy」を含めるべきです)。「init」はメモリを割り当てないため、オブジェクト(コンストラクタファッション)。割り当てられたオブジェクトを受け取り、関数がそのようにinitのみを呼び出した場合、それは解放されません。

- (void)func:(NSObject*)allocd_but_not_init
{
    [allocd_but_not_init init];
}

これは、すでに開始したメモリよりも多くのメモリを消費しません(initがオブジェクトをインスタンス化しないと仮定しますが、とにかくそれらの責任はありません)。


ドレインに関する情報が正しくない場合、この回答を受け入れられたままにしておくのは気分が悪いです。developer.apple.com/documentation/Cocoa/Reference/Foundation/…を参照してください。更新すると、再度同意します。
James Sumners、

返信の不正確な点は何ですか?(上記のように)ガベージコレクションされた環境では、ドレインはAutoReleasePoolを削除しないため、リリースを使用しない限りメモリリークします。私が挙げた引用は、馬の口からのもので、ドレーンに関する文書でした。
Loren Segal

1
ローレン:GCでは、-[NSAutoreleasePool drain]がコレクションをトリガーします。-retain、-release、および-autoreleaseはすべてコレクターによって無視されます。これが、GCの自動解放プールで-drainが使用される理由です。
クリスハンソン

「ドレイン」のドキュメンテーション:管理されたメモリ環境では、これはリリースの呼び出しと同じように動作します。したがって、リリースの代わりに「ドレイン」を使用しても、メモリリーク発生しません
mmalc 2008年

-[NSAutoreleasePool release]ガベージコレクションされた環境では何もできません。-[NSAutoreleasePool drain]参照カウントとガベージコレクションの両方の環境で動作します。
ジョナサンスターリング
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.