SharpLab で理解する「参照型」のメモリ配置
― Book クラスと string フィールドを題材に
目次
はじめに
C# の 参照型 (class) が実行時にどのようにヒープとスタックへ展開されるかを視覚的に確認できるツールとして、SharpLab には Inspect.* API が用意されています。本記事では次のコードを SharpLab で実行した際に表示される MemoryGraph を読み解き、参照・ヒープ・スタック・ガベージコレクション (GC) の関係を解説します。
Book book1 = new Book();
Inspect.MemoryGraph(book1); // ①
book1.Title = "吾輩は猫である";
Inspect.MemoryGraph(book1); // ②
Inspect.Stack(book1); // ③
Inspect.Heap(book1); // ④
Book book2 = new Book();
Inspect.MemoryGraph(book2); // ⑤
Inspect.Stack(book2); // ⑥
Inspect.Heap(book2); // ⑦
class Book
{
public string Title = ""; // 明示的に空文字で初期化
}

ポイント
- Inspect.MemoryGraph … 変数から到達可能なオブジェクトグラフ全体を描画
- Inspect.Stack … スタックフレーム上のローカル変数を描画
- Inspect.Heap … 対象オブジェクトのヒープ内レイアウトを描画
1. スタックとヒープに現れる構造
1-1. 変数 book1 / book2

- スタックに置かれるのは「ポインタ値」。SharpLab ではbook1: Book ref といったラベルで枠が描かれ、16 進数の値が格納されています。
- それぞれ 別のアドレスを保持しており、後述の Book 実体を指しています。
1-2. Book オブジェクト本体
- ヒープ上に 二つ の Book インスタンスが生成されます。
- 各インスタンスは
- header(同期ブロックなど)
- type handle(型情報へのポインタ)
- フィールド Title(String への参照)をメンバーとして持ちます。
1-3. フィールド Title

- フィールド自体も 参照です。
- コンストラクタ内で “" を代入しているため、初期状態では 空文字を指す String へのポインタが入っています。
- 代入後 (book1.Title = “吾輩は猫である") は 別の String インスタンスを指すようにポインタが更新され、Book のサイズは変わりません。
2. スクリーンショットの読み方(抜粋)
SharpLab の枠 | 意味 | 注目点 |
---|---|---|
book1: Book ref(Stack) | スタックフレーム内のローカル変数 book1 | 中身はヒープ先頭アドレスへの 64bit 値 |
Pointer to Book → Book at 0x… | 上記ポインタが指すヒープ領域 | 同一プログラム内のすべての Book が同じ type handle を共有 |
Title: String ref | Book のフィールド | 代入前は空文字インスタンス、代入後は新しいインスタンスを指す |
String: 吾輩は猫である | String オブジェクト本体 | 文字列は 不変 (immutable) なので書き換えではなく新規生成 |
3. 実験:SharpLab で確認してみよう
3-1. 参照共有の可視化
book2.Title = book1.Title; // 同じ String を共有
Inspect.MemoryGraph(book1);
Inspect.MemoryGraph(book2);
- どちらの Title も同一 String オブジェクトを指していることが図で確認できます。
3-2. 文字列の不変性
book2.Title = book2.Title + "(新装版)";
Inspect.MemoryGraph(book2);
- 連結結果は新インスタンス。旧インスタンスは到達不能なら GC の対象になります。
3-3. null と “" の違い
book2.Title = null;
Inspect.MemoryGraph(book2);
- Title フィールドが null 参照となり、空文字インスタンスとの違いを可視化できます。
4. ガベージコレクションとの関係
状態 | GC 対象になるか |
---|---|
book1 / book2 がスタックから参照されている | ならない |
どちらかの変数が null になり、他に参照がない | その Book と Title の String が 回収候補 |
同一 String を複数が共有し,全てが解放される | 共有された String も 回収候補 |
5. まとめ
- 参照型オブジェクトはヒープに実体、スタックに参照 (ポインタ)
- フィールドが参照型なら、オブジェクトの中にも参照が入る
- 代入は参照先の付け替えであり、オブジェクト内にデータがコピーされるわけではない
- string は不変で、内容変更は常に新インスタンス生成
- SharpLab の Inspect.* API を活用すると、こうした概念を視覚的に確認できる
次のステップ
- struct を使い 値型 と比較する
- List<T> のような コレクション を追加し、内部要素がどのようにヒープに配置されるか観察する
C# のメモリモデルを“頭の中の図”だけで理解するのは難しいものです。SharpLab でスタックとヒープを実際に覗きながら学習すると、参照・値コピー・GC の振る舞いが一気に腹落ちします。ぜひ授業や自習の場で試してみてください。
訪問数 4 回, 今日の訪問数 1回
ディスカッション
コメント一覧
まだ、コメントがありません