5

StackOverflowで尋ねられた質問を調べてきましたが、Objective-Cのメモリ管理については非常に多く、探していた答えを見つけることができませんでした。

問題は、新しく作成されたオブジェクト(NSMutableArrayなど)をコレクションに追加する前にautoreleaseを呼び出しても問題ない(そして推奨される)かどうかです。または、追加後に明示的にリリースする必要があります。(私はNSMutableArrayがオブジェクトを保持することを知っています)

これは私の質問を示しています:

シナリオA(自動リリース):

- (void) add {
   // array is an instance of NSMutableArray

   MyClass *obj = [[[MyClass alloc] init] autorelease];

   [array addObject:obj];
}

シナリオB(明示的なリリース):

- (void) add {
   // array is an instance of NSMutableArray

   MyClass *obj = [[MyClass alloc] init];

   [array addObject:obj];

   [obj release];
}

私は両方とも正しいと思いますが、私にはわかりません。そして、私は確かに好ましい方法が何であるかを知りません。

Objective-Cの達人はこれに光を当てることができますか?

4

7 に答える 7

12

私見、どちらが「正しい」かは好みの問題です。を使用しないことを主張するレスポンダーに同意しませんが、圧倒的にやむを得ない理由がない限りautorelease、使用することを好みます。autorelease私の理由をリストします。あなたのプログラミング スタイルに適しているかどうかを判断してください。

Chuck が指摘したように、自動解放プールを使用すると何らかのオーバーヘッドが発生するという半都市伝説があります。これは真実からかけ離れたものではなく、Shark.app を使用してコードからパフォーマンスの最後のビットを絞り出すために数え切れないほどの時間を費やした結果です。これを最適化しようとすることは、「時期尚早の最適化」の領域に深く入り込みます。Shark.app が、これが問題である可能性があるという確固たるデータを提供する場合に限ります。

他の人が指摘したように、自動解放されたオブジェクトは「後で解放されます」。これは、その「後の時点」が転がるまで、それらが残り、メモリを占有することを意味します。「ほとんど」の場合、これは、次のイベント (タイマー、ユーザーが何かをクリックするなど) まで実行ループがスリープする前のイベント処理パスの最後にあります。

ただし、場合によっては、これらの一時オブジェクトを後でではなくすぐに削除する必要があります。たとえば、巨大な数メガバイトのファイル、またはデータベースからの数万行を処理する必要があります。NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];これが発生した場合、適切に選択されたポイントに a を配置し、続い[pool release];て下部に aを配置する必要があります。これはほとんどの場合、ある種の「ループ バッチ処理」で発生するため、通常は重要なループの最初と最後で発生します。繰り返しますが、これは勘に基づくのではなく、証拠に基づく必要があります。Instrument.app の ObjectAlloc は、これらの問題点を見つけるために使用するものです。

ただし、私が を好む主な理由は、リークのないプログラムを作成する方がautoreleaseはるかに簡単だからです要するに、ルートを選択した場合、最終的に が に送信されることを、あらゆる状況下で保証する必要があります。これは簡単そうに見えて、実際にやってみると意外と難しいものです。たとえば、あなたの例を見てください:releasereleasereleaseobj

   // array is an instance of NSMutableArray
   MyClass *obj = [[MyClass alloc] init];
   [array addObject:obj];
   // Assume a few more lines of work....
   [obj release];

なんらかの理由で、何かが、どこかでarray、おそらく結果を処理するために何らかのメソッドを使用した結果として、可変であるという仮定に微妙に違反し、処理された結果を含む返された配列が として作成されたと想像してくださいNSArrayaddObject:その immutableに送信すると、例外がスローされ、そのメッセージNSArrayは送信されません。または、 d と必要なへの呼び出しの間のどこかで何か問題が発生した可能性があります。たとえば、何らかの条件を確認してすぐに誤って、 への呼び出しが後で行われる必要があることを忘れてしまった場合などです。objreleaseobjallocreleasereturn()release

オブジェクトをリークしました。そして、おそらく、あなたが漏らしている場所と理由を突き止めようとして、数日間サインアップしたことでしょう。経験上、あなたは何時間もかけて上記のコードを見て、非常に明確objrelease. それから数日後、あなたは問題の原因を悟り、宗教的なひらめきとしか言いようのないものを体験するでしょう。

ケースを考えてみましょうautorelease

   // array is an instance of NSMutableArray
   MyClass *obj = [[[MyClass alloc] init] autorelease];
   [array addObject:obj];
   // Assume a few more lines of work....

obj今では、非常に珍しい、または例外的なコーナーケースであっても、誤ってリークすることは事実上不可能であるため、何が起こっても問題ではありません.

于 2009-07-19T01:22:05.743 に答える
7

どちらも正しく、期待どおりに機能します。

私は個人的に後者の方法を使用することを好みますが、それはオブジェクトがいつリリースされるかを明示したいからです。オブジェクトを自動リリースすることで、「このオブジェクトは将来の任意の時点でリリースされる」と言っているだけです。つまり、自動解放されたオブジェクトを配列に配置し、配列を破棄しても、オブジェクトは(おそらく)まだ存在している可能性があります。

後者の方法では、オブジェクトは配列とともにすぐに破棄されます(その間に他に何も発生せず、保持されていない場合)。使用しているメモリの量に注意する必要があるメモリに制約のある環境(iPhoneなど)にいる場合は、後者の方法を使用して、オブジェクトがあまり残っていないようにします。どこかにNSAutoreleasePool。メモリ使用量があなたにとって大きな関心事ではない場合(そしてそれは通常私にとってもそうではありません)、どちらの方法も完全に受け入れられます。

于 2009-07-18T15:30:07.087 に答える
3

どちらも正しいですが、オーバーヘッドがまったくないため、Bの方が適している場合があります。自動解放により、自動解放プールがオブジェクトを担当します。これにはごくわずかなオーバーヘッドがあり、もちろん、関係するオブジェクトの数が掛けられます。

したがって、1つのオブジェクトでAとBはほぼ同じですが、配列に追加するオブジェクトが多数あるシナリオでは、Aを使用しないでください。

さまざまな状況で、自動解放は、スレッドの終わりで多くのオブジェクトの解放を遅らせ、蓄積する可能性があります。これは最適ではない可能性があります。とにかく自動解放は明示的な介入なしに多く発生することに注意してください。たとえば、多くのゲッターは次のように実装されます。

return [[myObject retain] autorelease];

したがって、ゲッターを呼び出すときはいつでも、自動解放プールにオブジェクトを追加します。

于 2009-07-18T15:29:17.837 に答える
0

autoreleaseメッセージは、アプリケーションのメッセージループが繰り返されるまで(つまり、ユーザー入力に応答してすべてのメソッドの実行が終了するまで)実行されないため、いつでも送信できます。

http://macdevcenter.com/pub/a/mac/2001/07/27/cocoa.html?page=last&x-showcontent=text

于 2009-07-18T15:30:07.167 に答える
0

'オブジェクトをalloc作成したら、ある時点でそれを解放するのがあなたの仕事です。両方のコードスニペットは、同じように正しく機能しますが、そのautorelease方法は潜在的に低速です。

autorelease個人的には、入力が簡単でボトルネックになることはほとんどないため、この方法が好きです。

于 2009-07-18T15:30:52.080 に答える
0

どちらも大丈夫です。「オーバーヘッド」などの理由で自動リリースを避けるように言われる人もいますが、実際にはオーバーヘッドはありません。先に進んでベンチマークを行い、「オーバーヘッド」を見つけてください。あなたがそれを避ける唯一の理由は、iPhoneのようにメモリが不足している状況にあることです。OS Xでは、実質的に無制限のメモリがあるため、大きな違いはありません。自分にとって最も便利な方を使用してください。

于 2009-07-18T15:39:35.367 に答える
0

私は、johne が呼んでいるように、簡潔さと「安全性」のために A (自動リリース) を好みます。コードが簡素化され、問題に遭遇したことはありません。

つまり、今日まで: ブロックを配列に追加する前にブロックを自動解放する際に問題がありました。私のスタックオーバーフローの質問を参照してください: [myArray addObject:[[objcBlock copy] autorelease]] は、配列の解放時にクラッシュします(更新: 問題は私のコードの別の場所にあることが判明しましたが、それでも autorelease の動作には微妙な違いがありました… )

于 2011-05-02T08:33:06.723 に答える