・リファレンスカウンタ方式
・ガーベジコレクション
ガーベジコレクションは2.0から採用された自動メモリ管理の仕組みで、Javaのガーベジコレクションと同じ要領である。
一定時間毎に不必要な(参照されていない)クラスを探しだし、解放していく。
これは後にとっておくとして・・・
まずはリファレンスカウンタ方式から詳しく見ていく。
一言でいうと、クラスがいくつ参照されているかをカウンタで管理し、0になったらメモリを解放するという仕組みである。
具体的には alloc init された時点で、インスタンスはカウンタを1とする。
以下例:
id foo = [[Foo alloc] init]; // fooインスタンにカウント1が刻まれる
[foo release]; // fooインスタンスのカウントは0となり、メモリがリリースされる
id foo2 = [[Foo alloc] init]; // foo2インスタンスにカウント1が刻まれる
id hoge = [[Hoge alloc] init];
[hoge setFoo:[foo2 retain]]; // HogeインスタンスにはsetFooでfooを参照する機能がある。この時点でfoo2インスタンスにカウント2が刻まれる
[foo2 release]; // foo2のカウントが1に減る
[foo2 release]; // foo2のカウントが0となり、メモリがリリースされる
・retain メソッドでカウントを+1する。このメソッドは自身を返す。
・release メソッドでカウントを−1する。
・現在のカウント数は retainCount メソッドで見る事が出来る。
・dealloc でメモリをリリース出来るが、これはカウンタに関係なくリリースされてしまうので使うべきではない。
でもいちいち手動でリリースしてたらきりがない!
そこで dealloc をオーバーライドして、インスタンスが解放される時にインスタンスが保持するオブジェクトをリリースするのだ。
以上をふまえて簡単なテストプログラム
ReferenceCounterクラス
#import
@interface ReferenceCounter : NSObject {
id obj;
}
-(void)setObj:(id)_obj;
@end
@implementation ReferenceCounter
-(void)setObj:(id)_obj {
obj=[_obj retain]; // 何かオブジェクトがセットされる。ただ代入するのではなく、使用するよ!とカウンタを+する。
}
-(void)dealloc {
[obj release]; // 自身がリリースされるまえに、自分がもってるオブジェクトをリリースする。
[super dealloc]; // 自身のリリース
}
@end
int main(int argc, char *argv[]) {
id foo=[[NSObject alloc] init];
printf("retainCount: %d\n",[foo retainCount]);
id rctest=[[ReferenceCounter alloc] init]; // テストクラスを作成
[rctest setObj:foo]; // テストクラスになんかオブジェクトをセットする
printf("retainCount: %d\n",[foo retainCount]);
[foo release]; // オブジェクトをリリース
printf("retainCount: %d\n",[foo retainCount]);
[rctest release]; // テストクラスをリリース
return 0;
}
・foo インスタンスが alloc されて foo = 1 カウンタがつく
・rctest インスタンスが alloc されて rctest = 1 カウンタがつく
・rctest に foo をセットする。setter内で foo を retain するので foo=2 になる
・foo インスタンスを release する。 foo=1 になる
・rctest をリリースする。rctest=0になり、dealloc がよばれ rctest内のobj(foo)がreleaseされる。 foo=0になる
出力は以下のような感じ
retainCount: 1
retainCount: 2
retainCount: 1
なるほど、オブジェクト思考っぽい。
この考えは普通にJavaでも活かせる気がする!
0 件のコメント:
コメントを投稿