スタックメモリとヒープメモリ
概要
メモリには大きく分けて2種類ありそれぞれスタックメモリとヒープメモリと呼ばれています。 変数を宣言し値を代入するとメモリ上に値が格納されます。値型の変数と参照型の変数でメモリの使われ方が異なります。 変数がどのようにメモリを使用するかを順番に解説していきます。 説明は便宜上簡略化した仕組みで解説をしています。実際のメモリの動作はもう少し複雑になるのでご注意ください。
値型の変数とスタックメモリ
まずは値型の変数とメモリについて解説していきます。以下のようなコードを記述します。
Int32 a = 0;
Int32 b = 1;
{
    Int32 c = 2;
}
Int32 d = 3;
1行目の
Int32 a = 0;
を実行するとスタックメモリ上に以下のようにデータが保存されます。
2行目の
Int32 b = 1;
が実行されるとメモリは以下のようになります。
このようにメモリに保存したい値がどんどん積まれていくように見えるのでスタック(積みあげる)メモリと呼ばれています。
Int32 c = 2;
のコードが実行された直後のメモリの状況は以下のようになります。
変数の範囲は{}の間で有効です。変数cは括弧の中にあるのでこの括弧を抜けた瞬間にメモリからクリアされます。
{
    Int32 c = 2;
}
括弧を抜けた瞬間のメモリの状況は以下のようになります。
最後にこのコードを実行するとまたメモリが詰まれていきます。
Int32 d = 3;
メモリの状況は以下のようになります。
値型の変数のサイズ
値型では変数の種類によってどのくらいのメモリを消費するかは決まっています。 Int16であれば16ビット、Int32であれば32ビット、Booleanであれば1ビットといった形です。 以下のようなコードを考えてみます。
Byte a = 100;
Boolean b = true;
UInt16 c = 99;
メモリのサイズを1マス1ビットとすると正確には以下のようになるはずです。
例で示した下の状況は1マスが32ビットとして表現してあります。 実際には1マスに32個のセルが入っていてそれによって32ビットの数字を表現していると考えてください。
参照型とヒープメモリ
C#ではクラスを宣言すると参照型として振舞うようになります。以下のようなクラスを定義します。
public class Person
{
    public String Name { get; set; }
    public Int32 Age { get; set; }
    public User(String name, Int32 age)
    {
        this.Name = name;
        this.Age = age;
    }
}
このクラスをMainメソッドで宣言します。
static void Main(string[] args)
{
    Person p = new Person("Higty", 24);
}
メモリは以下のようになります。
赤い数字はヒープメモリ上のアドレス(場所)を示します。ヒープメモリのアドレスの番号は以下のように上から順番に数字を振るものとします。
変数 p はヒープメモリ上の番地0から2マス分の領域に値が格納されています。確保する領域のサイズはクラスを定義したときに決まります。 32bitのOSにおける参照型のサイズは32bitになります。値型の場合はそれぞれの型によってサイズが決まっています。Int16であれば16bit、Byteであれば8bitです。 クラスに定義されたメンバー変数が多ければ多いほど領域のサイズも大きくなります。 この例の場合、1マス目にはNameプロパティのアドレスの値、2マス目にはAgeの値が格納されることになります。
1マス目のNameプロパティはString型で参照型なので実際の文字の値は番地2の部分に格納されています。

PersonクラスにParentプロパティを追加して以下のように書き換えます。
public class Person
{
    public String Name { get; set; }
    public Int32 Age { get; set; }
    public Person Parent { get; set; }
    public User(String name, Int32 age)
    {
        this.Name = name;
        this.Age = age;
    }
}
以下のようにMainメソッド内のコードを記述して実行します。左端の数字は行番号です。
Person p1 = new Person("Higty", 24);
Person p2 = new Person("Suzuki", 40);
p1.Parent = p2;
1行目の実行が終わるとメモリは以下のようになります。
2行目の実行が終わると p2 用のメモリが確保されメモリは以下のようになります。
3行目の実行が終わるとヒープメモリの番地2の値がnullから4に変更されメモリは以下のようになります。
Create at 2012/8/9 LastUpdate 2012/8/17