連載
» 2009年07月23日 00時00分 UPDATE

Cocoaの素、Objective-Cを知ろう(7):メモリ管理を理解する(前編) (1/2)

iPhone用アプリケーション開発で注目を集める言語「Objective-C」。C++とは異なるC言語の拡張を目指したこの言語の基本を理解しよう(編集部)

[竹下肯己,株式会社 qnote]

 あらゆるアプリケーションは、システムのメモリ上に展開されて動作します。

 メモリは限られた資源なので、アプリケーションは資源を無駄に消費しないよう自己管理しながら動作する必要があります。この動作を実現するのが、開発者によるメモリ管理の実装です。

 新しく登場した言語のなかにはメモリ管理が自動で行われる(言語のエンジン部分で暗黙的にメモリ管理がされている)ものが多いため、開発者がメモリ管理を意識することが少なくなっています。

 実際、Objective-Cでも、Objective-C 2.0から(Mac OS X 10.5 から)はガベージコレクションという自動メモリ管理の仕組みが導入されています。

 しかし、自動でのメモリ管理は、すべてのアプリケーションにおいて必ずしも効率的であるとは限りません。よりシビアにメモリ管理を行う必要があるアプリケーションでは、開発者が場面に応じて明示的にメモリの割り当てや解放を行うことで、スマートでパフォーマンスに優れたプログラムを作ることができます。

 そもそもガベージコレクションが利用できないプラットフォーム(Mac OS X 10.4 以前や、iPhoneなど)のことも考慮しなければなりません。

 連載の最後の2回を使って、Objective-Cにおけるメモリ管理の基本的な仕組みについて解説したいと思います。

オブジェクトがどれだけ必要とされているか

 メモリ管理とは具体的に何を行っているのでしょうか。それは、必要なときにプログラムのデータをメモリ上に展開(メモリ領域を割り当て)し、必要がなくなったら、そのメモリ領域を解放することです。

 管理の対象となるデータは、オブジェクト指向の言語では、多くの場合クラスのインスタンスです。クラスインスタンスの生成(メモリ割り当て)が必要になるタイミングについては、あまり迷うことはないでしょう。問題は、それをいつ解放するかです。

 インスタンスを生成する側の閉じた文脈のなかでは、インスタンスの要不要は比較的簡単に判断できるかもしれません。しかし、これまでも見てきたように、生成したインスタンスは、メソッドを介して別のオブジェクトに渡される場合があります。渡した先の文脈で、そのインスタンスがいつまで必要とされるのか、不要になったらちゃんと解放してくれるのか、といったことは知る由もありません。

 このような問題に対処するため、Objective-Cでは、あるオブジェクトがどれだけ必要とされているか(あるいは不要と判断されたか)を、単純にプラスマイナスでカウントしていく仕組みを採用しています。この仕組みを参照カウンタといいます。

 例えば、プログラムロジックのある場所で「このオブジェクト、ちょっとしばらく使うから、破棄(メモリの解放)しないでね」という宣言をしておきます。すると、参照カウンタは1プラスされます。

 その後、「さっき必要っていったけど、使い終わったから少なくとも僕のところではもう要らないよ」といった宣言をします。すると、参照カウンタは1マイナスされます。

 このような、オブジェクト所有権の獲得と放棄(参照カウンタの増減)を、文脈ごとに自分の守備範囲内で行います。別のオブジェクトに渡してしまったら、そちらでどう扱われるかは守備範囲外となりますので関知しません。

 参照カウンタが0になると、そのオブジェクトは誰も必要としていないということになるので、そのメモリ領域は解放されます。

参照カウンタの動きを見てみよう

 「このオブジェクトを消さないで!」の宣言にはretainというメソッドを、「もう要らなくなったよ!」という宣言にはreleaseというメソッドを利用します。どちらもNSObjectのメソッドなので、あらゆるクラスのオブジェクトから呼び出すことができます。

 まず、参照カウンタの増減を簡単なサンプルで確認してみましょう。あるオブジェクトの参照カウンタの値は、retainCountというメソッドで取得できます。

01 #import <Foundation/Foundation.h>
02 
03 int main(void) {    
04 
05     NSObject *myObj = [[NSObject alloc] init]; // (a)
06     printf("%d\n", [myObj retainCount]);       //
07 
08     [myObj retain];                            // (b)
09     printf("%d\n", [myObj retainCount]);       //
10 
11     [myObj release];                           // (c)
12     printf("%d\n", [myObj retainCount]);       //
13 
14     [myObj release];                           // (d)
15     //printf("%d\n", [myObj retainCount]);     // (e)
16 
17     return 0;
18 }
main.m

a.インスタンスを生成した時点(allocメソッドを実行した時点)で、参照カウンタは1になります。

b.retainメソッドで参照カウンタを1プラスします。この時点で参照カウンタは2になります。

c.releaseメソッドで参照カウンタを1マイナスします。この時点で参照カウンタは1になります。

d.さらにreleaseメソッドを呼び出して、参照カウンタをマイナスします。この時点で参照カウンタは0になり、オブジェクトは解放されます。

e.すでに解放されているので、このオブジェクトにアクセスできません。サンプルコード中のコメントを外すとエラーになります。

       1|2 次のページへ

Copyright© 2017 ITmedia, Inc. All Rights Reserved.

@IT Special

- PR -

TechTargetジャパン

この記事に関連するホワイトペーパー

RSSについて

アイティメディアIDについて

メールマガジン登録

@ITのメールマガジンは、 もちろん、すべて無料です。ぜひメールマガジンをご購読ください。