[PR]
2024年11月27日
×
[PR]上記の広告は3ヶ月以上新規記事投稿のないブログに表示されています。新しい記事を書く事で広告が消えます。
iPhoneアプリケーション開発でautoreleaseが非推奨の理由
2009年09月22日
アップル社公式の開発ガイドなどでは、iPhone OSをターゲットとしたアプリケーションを開発する場合、autoreleaseはなるべく避けるようにと書いてあります。この記事ではその理由を掘り下げてみようと思います。
この理由を明かす前に、まず推奨となっているretain countでの管理と、autoreleaseでの管理の違いを説明します。retain countで管理されているオブジェクトは、それをメモリー上に残しておきたい場合にretain countを0より大きい値になるようにしておきます。そのオブジェクトがallocやretainされるとカウントが増加し、releaseされればカウントが減少します。カウントが0になった状態でrun loop(ユーザーからの入力などのイベント処理)に入ると、そのオブジェクトはメモリー上から消滅します。この方法だと、オブジェクトは必要な時にメモリーを確保して、不要になると早いうちに解放されます。解放されたメモリーは別のオブジェクトの保持等にまわす事ができるので、無駄が少なくなります。
では非推奨のautoreleaseではどうなっているかというと、NSAutoreleasePoolという仕掛けがあり、この中にオブジェクトが追加されるようになっています。このNSAutoreleasePoolもオブジェクトで、これは前述のretain countで管理されています。この中に入っているオブジェクトは、それを入れている器であるNSAutoreleasePoolが解放されたときに、同時に解放されるようになっています。Xcodeでテンプレートからアプリケーションのプロジェクトを作った場合、このNSAutoreleasePoolは1つだけ自動で作られるようになっていますが、問題はこのNSAutoreleasePoolが解放されるタイミングが、「アプリケーションを終了したとき」になることです。従って、後述する対策を行わずにいると、アプリケーションで作られたautorelease付きのオブジェクトや、クラスメソッドと呼ばれる+印で始まるメソッドから返ってきたオブジェクトは全てこのNSAutoreleasePoolに入れられてしまい、アプリケーションを終了するまで解放されずに残ってしまうのです。これらによってメモリーが消費されてしまうと、アプリケーションが使えるメモリー領域はどんどん狭くなってしまいます。Mac OS Xで動いているマシンであればメモリーの量もそれなりにあるのであまり問題になりませんが、iPhone OSではそこまでメモリーを贅沢に使えるわけでもないので、アプリケーションを終了するまで誰も使えなくなるゴミ領域はなるべく作らない方が良いことになります。それこそがautorelease非推奨の理由なのです。
とはいえ、クラスメソッドには他で代替できないものや、代替可能でも長いコードを書かなければならない場合等もあります。そのためにautoreleaseオブジェクトの解放タイミングを早める対策方法も用意されています。実はNSAutoreleasePoolは何個も作る事ができ、メソッドの始めにNSAutoreleasePoolオブジェクトを作成すると、そのメソッド内で作られたautoreleaseオブジェクトは全てそのNSAutoreleasePoolオブジェクトの管理下に置かれます。そのため、メソッドから抜ける前にそれを解放すると、管理下にあるautoreleaseオブジェクトも同時に解放されるようになるのです。つまり、
このように書いている場合と大差ないものと思われます。大量に一時オブジェクトを作るようなメソッドでこのような対策を行っておけば、メモリーのゴミ領域を削減することができるわけです。
2009年10月2日追記
一般的なアプリケーションではイベントループの開始時点で自動的にプールが作成される仕組みもあるため、上に書いてあるように、自分でプールを追加しないとアプリケーション終了までオブジェクトが消滅しないということはありませんでした。ただし意図的に別スレッドを作った場合などはオブジェクトが残ることがあるので、このような場合は明示的にプールを作成、解放をしたほうが良いでしょう。
この理由を明かす前に、まず推奨となっているretain countでの管理と、autoreleaseでの管理の違いを説明します。retain countで管理されているオブジェクトは、それをメモリー上に残しておきたい場合にretain countを0より大きい値になるようにしておきます。そのオブジェクトがallocやretainされるとカウントが増加し、releaseされればカウントが減少します。カウントが0になった状態でrun loop(ユーザーからの入力などのイベント処理)に入ると、そのオブジェクトはメモリー上から消滅します。この方法だと、オブジェクトは必要な時にメモリーを確保して、不要になると早いうちに解放されます。解放されたメモリーは別のオブジェクトの保持等にまわす事ができるので、無駄が少なくなります。
では非推奨のautoreleaseではどうなっているかというと、NSAutoreleasePoolという仕掛けがあり、この中にオブジェクトが追加されるようになっています。このNSAutoreleasePoolもオブジェクトで、これは前述のretain countで管理されています。この中に入っているオブジェクトは、それを入れている器であるNSAutoreleasePoolが解放されたときに、同時に解放されるようになっています。Xcodeでテンプレートからアプリケーションのプロジェクトを作った場合、このNSAutoreleasePoolは1つだけ自動で作られるようになっていますが、問題はこのNSAutoreleasePoolが解放されるタイミングが、「アプリケーションを終了したとき」になることです。従って、後述する対策を行わずにいると、アプリケーションで作られたautorelease付きのオブジェクトや、クラスメソッドと呼ばれる+印で始まるメソッドから返ってきたオブジェクトは全てこのNSAutoreleasePoolに入れられてしまい、アプリケーションを終了するまで解放されずに残ってしまうのです。これらによってメモリーが消費されてしまうと、アプリケーションが使えるメモリー領域はどんどん狭くなってしまいます。Mac OS Xで動いているマシンであればメモリーの量もそれなりにあるのであまり問題になりませんが、iPhone OSではそこまでメモリーを贅沢に使えるわけでもないので、アプリケーションを終了するまで誰も使えなくなるゴミ領域はなるべく作らない方が良いことになります。それこそがautorelease非推奨の理由なのです。
とはいえ、クラスメソッドには他で代替できないものや、代替可能でも長いコードを書かなければならない場合等もあります。そのためにautoreleaseオブジェクトの解放タイミングを早める対策方法も用意されています。実はNSAutoreleasePoolは何個も作る事ができ、メソッドの始めにNSAutoreleasePoolオブジェクトを作成すると、そのメソッド内で作られたautoreleaseオブジェクトは全てそのNSAutoreleasePoolオブジェクトの管理下に置かれます。そのため、メソッドから抜ける前にそれを解放すると、管理下にあるautoreleaseオブジェクトも同時に解放されるようになるのです。つまり、
- (void)myMethod {
NSAutoreleasePool *myAutoreleasePool = [[NSAutoreleasePool alloc] init];
NSString *string = [NSString stringWithString:@"myAutoreleasePool管理オブジェクト"];
NSLog(string);
[myAutoreleasePool release];
}
- (void)myMethod {
NSString *string = [[NSString alloc] initWithString:@"retain count管理オブジェクト"];
NSLog(string);
[string release];
}
このように書いている場合と大差ないものと思われます。大量に一時オブジェクトを作るようなメソッドでこのような対策を行っておけば、メモリーのゴミ領域を削減することができるわけです。
2009年10月2日追記
一般的なアプリケーションではイベントループの開始時点で自動的にプールが作成される仕組みもあるため、上に書いてあるように、自分でプールを追加しないとアプリケーション終了までオブジェクトが消滅しないということはありませんでした。ただし意図的に別スレッドを作った場合などはオブジェクトが残ることがあるので、このような場合は明示的にプールを作成、解放をしたほうが良いでしょう。
PR
Comment