通常変数の解放のタイミング - Automatic Reference Counting

SPECIAL


通常変数の解放のタイミング

ARC (Automatic Reference Counting) を使用することで、これまで行っていた retain や release といったコーディングが不要になって、ソースコードがとても単純になります。

ただ、これまで自分でやっていたメモリ管理まわりの制御が自動化されるため、その動きをなんとなくでも把握していないと、逆に混乱してしまう心地がします。

 

たとえば、NSString クラスの文字列を作って、それを NSLog で出力するプログラムを ARC で書くと次のようになります。

NSString* value;

 

value = [[NSString alloc] initWithString:@"出力文字列"];

 

NSLog(value);

コードは以上で終わりで、その下に解放のためのコードは続きません。

ARC に慣れないうちは、これを見るとメモリーリークしているように見えてしまいますけど、これで問題なく動作してくれます。

ちなみに上記のコードの場合、"value" 変数が解放されるタイミングは、その変数を宣言したコードが所属するスコープを抜けた直後になります。

つまり、メソッド内での変数宣言であればそれを抜けるときですし、if 文やその他の中括弧で括られたブロック内での宣言であればそのブロックを抜けるときに、解放される感じになります。

 

従来もこれに似た記しかたはありましたけど、その場合には autorelease を指定するか "stringWithString:" メソッドを使用して、暗黙的に autorelease されたオブジェクトを取得する必要がありました。

また、その時の解放のタイミングは、とくに何もしなければ、変数宣言がスコープを抜けるよりも先の、オートリリースプールを解放するタイミングでした。

 

ARC でも "stringWithString:" を使用することができますが、その場合のコードは先ほどの "initWithString:" とほぼ同じ感じになります。

NSString* value;

 

value = [NSString stringWithString:@"出力文字列"];

 

NSLog(value);

このコードなら、従来の書き方としても正しい感じで、"value" 変数の値はオートリリースプールを抜けるタイミングで解放されます。

ただ、個人的にはこの autorelease を活用した方法よりは init による retain の方が良いように思います。

というのも、init による retain の方は、宣言された変数がスコープを抜けたタイミングでリリースされるので、当然スコープを抜ければその変数は使用しないため、効率の良い解放タイミングになります。一方 autorelease による方はというと、所属しているオートリリースプールを抜けるまで解放されないため、存在する必要のない変数が、しばらくの間メモリに残ってしまう感じになります。

 

なお、スコープを抜ける前でも、任意のタイミングで解放を要求することができます。

value = nil;

このように nil を代入することで、そこに代入されていたインスタンスが不要となったことを明示することができます。

retain されたオブジェクトが格納されている変数にいきなり nil を代入するのは、慣れないとかなり抵抗を感じますけど、でもこれで大丈夫です。

 

そしてこのとき、autorelease なオブジェクトと retain なオブジェクトとでは、内部的な意味合いが異なるようです。

autorelease なオブジェクトでは nil を代入することで、当然その変数は nil オブジェクトを指すことになり、その前に代入されていたオブジェクトはオートリリースプールの終了を以て解放される感じです。

retain なオブジェクトでは nil を代入することで、その変数は nil オブジェクトを指すことになると同時に、その前に代入されていたオブジェクトには release が指示される感じになるようです。当然、これにより誰からも参照されなくなった場合には、直ちに解放処理が行われるような感じでした。

[ Automatic Reference Counting 目次へ ]