autorelease
autorelease を使ってオブジェクトを生成した場合、そのオブジェクトはランループ(イベント処理の周期)終了時に解放される。
(例) NSMutableArray* array = [NSMutableArray array];
通常はこの仕組で問題ないが、バッチ的な処理を1箇所で行なう場合に autoreleaeを使うと解放されない大量の autoreleae属性のオブジェクトが残ってしまう場合がある。
(例) for (i=0; i < 100; i++) {
NSMutableArray* array = [NSMutableArray array];
:
時間のかかる処理
:
}これは、処理が終わるまでランループが終了しないので autoreleae属性のオブジェクトを解放するタイミングがこない為に起こる。これを回避するには autorelease を使うのをやめて自前で releaseする。
(例) for (i=0; i < 100; i++) {
NSMutableArray* array = [[NSMutableArray alloc] init];
:
時間のかかる処理
:
[array release];
}もしくは NSAutoreleasePoolを局所的に作る。
(例) for (i=0; i < 100; i++) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
NSMutableArray* array = [NSMutableArray array];
:
時間のかかる処理
:
[pool release];
}こうするとランループでの解放を待たずに autorelese属性のオブジェクトを解放することができる。NSAutoreleasePool はインスタンスが作成されると、それ以降の autorelease属性のオブジェクトを覚えていて、自分が releaseされるタイミングでこれらのオブジェクトへ releaseを投げて解放する。なお NSAutorelesePoolで管理される autorelease属性のオブジェクトの一覧はプライベートメソッドを使うと見ることができる。
NSLog(@"%@", [NSAutoreleasePool showPools]);こんな感じ。
- -- ---- -------- Autorelease Pools -------- ---- -- -
==== top of stack ================
0x620d860 (__NSArrayM)
0x6014b20 (NSCFNumber)
0x6019ae0 (__NSArrayI)
0x6019a70 (__NSArrayM)
0x6019b90 (__NSArrayI)
0x6002f00 (__NSArrayM)
0x6018030 (__NSArrayI)
0x60109b0 (__NSCFDictionary)
:
:
==== top of pool, 102 objects ================
0x60172d0 (__NSCFData)
0x6013210 (__NSCFData)
0x60130d0 (NSPathStore2)
0x60130b0 (NSCFString)
0x6012fd0 (NSCFString)
==== top of pool, 5 objects ================
==== top of pool, 0 objects ================[参考情報] [NSAutoReleasePool][CFRunLoop] NSAutoReleasePoolの管理者は誰であるべきか - Ni chicha, ni limona - 平均から抜けられない僕 - iPhoneアプリ開発グループ
サンプル
効果を確認する為サンプルを作ってみた。1MBの NSDataを連続で100回作成した時のメモリ利用量を NSLog()でデバッグコンソールへ書き出す。
こんな感じ。
#define BUFF_SIZE (1024*1024)
static char buff[BUFF_SIZE];
- (void)test
{
for (int i=0; i < 100; i++) {
NSAutoreleasePool* pool = [[NSAutoreleasePool alloc] init];
[NSData dataWithBytes:buff length:BUFF_SIZE];
メモリ利用量表示処理
[pool release];
}
NSLog(@"end");
}(1)NSAutoreleaePool なしの場合、(2)ありの場合、(3)ありで drainを使った場合の3つを調べた。
(1) NSAutoreleasePoolなしの場合
AutoreleasePoolTest[54677:207] RSS: 13.5 MB
AutoreleasePoolTest[54677:207] RSS: 14.8 MB
AutoreleasePoolTest[54677:207] RSS: 15.8 MB
AutoreleasePoolTest[54677:207] RSS: 16.8 MB
AutoreleasePoolTest[54677:207] RSS: 17.8 MB
:
:
AutoreleasePoolTest[54677:207] RSS: 110.9 MB
AutoreleasePoolTest[54677:207] RSS: 111.9 MB
AutoreleasePoolTest[54677:207] RSS: 112.9 MB
AutoreleasePoolTest[54677:207] endforループを1回るたびに 1MB増加しているのがわかる。(2) NSAutoreleasePoolありの場合(release解放)
AutoreleasePoolTest[54700:207] RSS: 13.5 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
:
:
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] endforループを繰り返しても一定のメモリ利用量から変化しない。ループ内で確保された NSDataはループの終わりできちんと解放されている。(3) NSAutoreleasePoolありの場合(drain解放)
AutoreleasePoolTest[54700:207] RSS: 13.5 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
:
:
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] RSS: 13.8 MB
AutoreleasePoolTest[54700:207] endrelease使用時と変わらず。と、NSAutoreleasePool の効果がよくわかった。
メモリ利用量の取得
現在使用しているメモリ量は task_info() を使うと取得できる。
[参考情報] 自分のアプリが使用しているメモリサイズを取得するには - The iPhone Development Playground
今回のコードはこんな感じ。
struct task_basic_info t_info;
mach_msg_type_number_t t_info_count = TASK_BASIC_INFO_COUNT;
if (task_info(current_task(), TASK_BASIC_INFO,
(task_info_t)&t_info, &t_info_count)!= KERN_SUCCESS) {
NSLog(@"%s(): Error in task_info(): %s",
__FUNCTION__, strerror(errno));
}
u_int rss = t_info.resident_size;
NSLog(@"RSS: %0.1f MB", rss/1024.0/1024.0);ソースコード
GitHubからどうぞ。
AutoreleasePoolTest at 2010-10-04 from xcatsan's iOS-Sample-Code - GitHub
参考情報
[NSAutoReleasePool][CFRunLoop] NSAutoReleasePoolの管理者は誰であるべきか - Ni chicha, ni limona - 平均から抜けられない僕 - iPhoneアプリ開発グループ
自分のアプリが使用しているメモリサイズを取得するには - The iPhone Development Playground
NSAutoreleasePool Class Reference
Memory Management Programming Guide: Autorelease Pools
- - - -
release と drain で挙動が違う現象に遭遇した。その為、今回サンプルを作って確認してみたのだがやはり差異はなかった。うーむ。



Responses
Leave a Response