スタックフレームとメモリ
値型の変数とスタックフレーム
OSによってアプリケーションの実行が開始されるとMainメソッドが実行されます。これはコンソールアプリでもWindowsFormアプリでも同じです。 Mainメソッドを実行するためにスレッドが1つ作成されます。このスレッドのことをメインスレッド(UIスレッド)といいます。 スレッド1つにつき1つのスタックメモリの領域が割り当てられます。例えば以下のようなサンプルコードで考えて見ます。
static void Main(string[] args)
{
    Int32 a = 6;
    Int32 d = Calc(a);
}
static Int32 Calc(Int32 b)
{
    Int32 c = b * 2;
    return c + 2;
}
左端の数字は行番号です。3行目の実行直後のメモリの状態は以下のようになります。
スタックメモリには3つの値が保存されています。
1.Mainメソッドの現在実行している行の行番号の値
2.Mainメソッドのパラメータ args の値
3.ローカル変数 a の値
が保持されています。 赤色で囲んだ部分が実行中の行番号を保存するための領域です。 緑色で囲んだ部分がメソッドのパラメータを保存するための領域になります。 水色で囲んだ部分がローカル変数を保存するための領域になります。 この3つの領域を合わせた領域のことをスタックフレーム(メソッドの状態)と呼びます。 1つのメソッドにつき1つスタックフレームが確保されて処理が実行されていきます。
4行目が実行され7行目まで進むとCalcメソッドのためのスタックフレームが確保されます。その結果メモリは以下のようになります。
8行目が実行されると以下のようになります。
9行目が実行され4行目まで戻るとCalcメソッドのスタックフレームがクリアされ以下のようになります。
10行目まで進んでMainメソッドの実行が終了するとスタックフレームがクリアされプログラムが終了します。 スタックメモリはスレッドごとに例えば1MBといったかたちで最大サイズが決まっています。 ローカル変数を大量に宣言したりメソッドの再起呼び出しを大量に行って最大サイズまで達してしまうとStackOverflowExceptionが発生します。 .NET Framework 2.0以降ではStackOverflowExceptionはキャッチすることができません。 プロセスは強制的に終了されます。メモリが不足しているのでデータベースへのログの記録なども不可能です。

whileや再起呼び出しをする場合はカウンタ用の変数を宣言しStackOverflowExceptionの発生を予防したほうがよいでしょう。 例えば1万回以上になったら自ら例外を投げるといった形で以下のように防御的プログラムを行います。
static void Method1()
{
    Int32 count = 0;
    while (true)
    {
        //Do something

        //some exit condition
        if (...) { break; }
        count += 1;
        if (count > 10000) { throw new MyCustomException(); }
    }
}
Create at 2012/8/17 LastUpdate 2012/8/17