C# メンバー変数 int number = 1; の内部構造

(インスタンス フィールド/static フィールド/const フィールドの相違点まで)


1. ソースコード上の宣言例

class Sample
{
    // インスタンス フィールド
    int number = 1;

    // static フィールド
    static int s_number = 1;

    // 定数フィールド
    const int C_NUMBER = 1;
}

2. コンパイル時 ― メタデータと IL の違い

種類生成される IL初期化コードが入る場所メタデータ登録
インスタンスnumberldarg.0, ldc.i4.1, stfld int32 Sample::numberインスタンス コンストラクタ (.ctor)Field テーブルに 1 エントリ
statics_numberldc.i4.1, stsfld int32 Sample::s_number型コンストラクタ(.cctor)Field テーブルに 1 エントリ
constC_NUMBERIL に フィールド記述なし。参照個所はすべて ldc.i4.1 即値Constant テーブルにリテラル値だけ登録

readonly フィールドはインスタンス/static と同じ IL を出力しますが、値の設定がコンストラクタに限定されるという言語仕様の制約が追加されるだけです。


3. 実行時メモリ配置

3.1 インスタンス フィールド

┌─ヒープ上の Sample オブジェクト────────────┐
│ [8 bytes] オブジェクトヘッダー            │
│ [8 bytes] EEType Ptr (64 bit)         │
│                                       │
│ [4 bytes] number = 1   ←★ここ          │
│   …(ほかのフィールドが続く)…             │
└───────────────────────────────────────┘
  • 配置順 はコンパイラがレイアウトを最適化(たとえば 64 bit でのアライメント調整)。
  • アクセス命令 は ldfld / stfld。
  • オブジェクトが GC に移動されると、フィールドも一緒にスライドします。

3.2 static フィールド

  • 型ごとに 1 つだけ確保される領域(“静的ヒープ”)。
  • CLR が型を 初回参照する瞬間に .cctor が実行され、値が代入される。
  • アクセス命令は ldsfld / stsfld。
  • ジェネリック型の場合、型引数ごとに別インスタンスの static が作られる(List<int> と List<string> では別領域)。

3.3 const フィールド

  • メモリ領域は存在しません
  • 参照箇所はすべてコンパイル時に即値へ置換されるため、実行時にロードされるものはありません。

4. JIT 後の命令例(x64, Debug ビルドの概念図)

種類代表的な機械語コメント
インスタンスmov dword ptr [rcx+offset], 1rcx は this ポインタ
staticmov dword ptr [rip+addr], 1型の静的領域アドレス
const(命令列に即値 1 が直書きされる)フィールドアクセスなし

5. ローカル変数との比較サマリ

項目ローカル変数インスタンス フィールドstatic フィールドconst
メモリスタックヒープ(オブジェクト内)静的ヒープなし
IL 命令stloc/ldlocstfld/ldfldstsfld/ldsfldldc.i4.*
GC の影響オブジェクトの移動でスライドAppDomain 単位 (世代 0 には載らない)
ラムダで捕捉DisplayClass に昇格変更なし変更なし

6. まとめ

  • メンバー変数(フィールド)はローカル変数とは配置先が異なり
    • インスタンス フィールドはオブジェクトの一部としてヒープに、
    • static フィールドは型単位の静的領域に、
    • const フィールドはそもそもメモリを消費せず即値埋め込み――という点が最大の差です。
  • IL でも命令セットが異なる (stfld / stsfld / ldc.*) ため、デバッガや ILDASM で確認すると違いが明確に分かります。
  • 逆に、値のサイズ (int なら常に 4 byte) や little-endian 順序といったビット表現自体はローカルでもフィールドでも変わりません。
訪問数 7 回, 今日の訪問数 1回

C#

Posted by hidepon