スタックとヒープによるメモリ管理
.NET Framework向けのプログラミング言語で書かれたプログラムは、管理されたコード(managed code)と呼ばれる。マネージドコードはメモリやセキュリティが管理されている。
スタック
スタックはLIFO(Last In First Out)でデータを管理する。値型のインスタンスに使われる。スタックによる領域の確保と解放は、スコープの出入りのタイミングで行われる。
ヒープ
ヒープは任意サイズのデータ量を任意の順序で確保・解放する。参照型のインスタンスに使われる。スタックとヒープを比較すると、スタックのほうが効率的であることが多い。スタックの制限内で特に問題のないデータに対しては、可能な限りスタックを利用すべき。
領域の確保と解放を繰り返すことで、使用中のヒープがメモリ上に散在する状態ができる断片化(fragmentation)の問題もある。
ガベージコレクション
C#では、ヒープ領域はガベージコレクションによって自動的に解放される。
値型と参照型
データのサイズが小さく、継承の必要のないものは値型として定義し、それ以外のものは参照型として定義する。
C#の型の分類
値型;構造体型(ユーザー定義構造体、数値、真偽値型)、列挙型
参照型;クラス、インターフェース、デリゲート、object、文字列、配列
ボックス化
値型のインスタンスをobject型の変数に代入することをボックス化という。ボックス化はできるだけ利用しないことが望ましい。
引数の参照渡し
メソッドの引数にrefキーワードをつけることで、参照渡しにできる。
static void Test(ref int a) {...}
static void Main()
{
int a = 0;
Test(ref a); // 呼び出し側でもrefキーワードが必要
}
out修飾子による出力引数」
メソッドで複数の熱尾を返したい場合、C#では、参照渡しではなく出力引数(out修飾子)を使うことができる。out修飾子を使えば、メソッド内で変数を初期化することができる。
static Test(int out a) {
a = 10;
}
static void Main() {
int a;
Test(out a); // aに10が代入される
}
Null許容型
通常、値型はnull値を取ることができない。C#にはNullable型という特殊な型があり、この型は値型でありながらnull値をとることができる。
Null許容型の定義は、値型の型名の後ろに?をつける。
int x = 1;
x = null; // コンパイルエラー
int? y = 1;
y = null; // コンパイルエラーにならない
Nullable型にはHasValueとValueというメンバーがあり、HasValueは値がnullならばfalseを返す。
Nullable型に対する演算の規則は何種類かあるが、たとえば 1 + null はnullになる。
?? 演算子を使うことで、値がnullか判別し、nullの場合には別の値を割り当てることができる。
int? x = null;
int y = x ?? 2; // xはnullなので2が代入される
x = 1;
int z = x ?? 2; // xはnullではないので1が代入される
リソースの破棄
ファイルのように、ガベージコレクションの管理対象外のリソースのことを、非管理リソース(Unmanaged Resource)と呼ぶ。
ファイルリソースを読み込む際は、適切な解放処理を行う必要がある。
通常、ファイルリソースの解放はtry-catch-finallyを使用してfinallyで行われることが多いが、C#では、usingステートメントを使うことで、ファイリソースの解放処理を簡単に書くことができる。
using (FileStream reader =
new FileStream(args[0], FileMode.Open))
{
// ファイルに対する操作
}
usingステートメントで使うリソース管理用クラスは、System.IDisposableインターフェースを実装している必要がある。