2011-01-14

Objective-Cのautorelease

Objective-Cのautoreleaseで、実際に何が起こるのか。オープンソースのCocoa実装GNUstepのソースコードで追いかけてみました。

http://togetter.com/li/88945 「autoreleaseのひみつ」

Cocoa全クラスの親クラス NSObjectにautoreleaseメソッドがあり、このautoreleaseメソッドは、NSAutoreleasePoolクラスのクラスメソッドaddObject:メソッドを呼ぶだけです。


[hoge autorelease];
/* [NSAutoreleasePool addObject:hoge]; と同じ */


NSAutoreleasePool addObject:は、そのスレッドのカレントプールにオブジェクトを追加します。メインスレッドの場合、通常NSRunLoopのループ先頭で確保されたプールになります。

NSRunLoopのループ終わりで、確保されていたプールが解放され、そのプールに入っているオブジェクト全てにreleaseが送られます。

図解すると次の通り。


(※ pool = [[NSAutoreleasePool alloc] init]; ですね)

NSAutoreleasePoolをalloc,initすると、そのプールがカレントプールになります。以下のようなスタックになってます。


(※ こちらもpool* = [[NSAutoreleasePool alloc] init]; ですね)

クラスメソッドを呼びまくったり([NSString stringほげ]とか)、autoreleaseを呼びまくるようなシチュエーション、たとえば、たくさん画像を読み込む場合。ファイルを読み込んだNSDataオブジェクト。それから作ったUIImageオブジェクト。サイズを変更したりしてまたUIImageオブジェクト。なんて時にautoreleaseしただけでreleaseされてないオブジェクトが大量に残ったりします。


for() {
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];

/* 画像読み込み処理 */;

[pool drain];
}


とすれば、こまめにreleaseすることができます。Mac OS Xでガベージコレクションいかしたプログラミングする時に役立つように、drainを使っておきましょう。GCされます。


メモリ管理全般の話は、Memory Management in Objective-Cがわかりやすいかと思います。iDeveloper TVのフリーセッションビデオです。Objective-Cのallocの前に、そもそもC言語のmallocで何が起きるのか、から入っています。


あ、そういえば、iPhone開発本「iOS 4プログラミングブック」(2011年1月27日発売) 344ページ中70ページくらい書いたりしています。BlocksとGrand Central Dispatchについて、本当に詳しく書きましたので、よろしければ是非。