FIG-059

スタックとヒープ — 値を渡すか、地図を渡すか

OS・低レイヤ 2026.06.26 公開 読了 約10分

プログラムが変数を置く場所には、大きく2つあります。スタックヒープです。同じ「代入」に見えても、値そのものを箱に入れるのか、実体の置き場所を指す「地図(ポインタ)」を入れるのかで、後からの書き換えの伝わり方がまるで変わります。

下の図1で、コードを1行ずつ実行してみてください。左のスタックと右のヒープがどう変化するか――とくに「コピーしたのに連動する/しない」の分かれ目を、目で追えます。

STEP EXECUTION — 1行ずつ実行してメモリの動きを見る
1 let a = 10;
2 let b = a;
3 b = 20;
4 let box = new Box(99);
5 let alias = box;
6 alias.value = 77;
STACK 値そのものを置く
a
b
box
alias
HEAP 実体を置く・住所がつく
0x7f Box { value: 99 }
(まだ何も確保されていない)
READY
「次へ」で1行ずつ実行します
スタックは「値そのもの」、ヒープは「実体」を置く場所です。コードを進めて、代入で値がコピーされるのか、それとも同じ実体を指すのかを確かめてください。
図1 — スタックの値コピーは独立、ヒープの参照コピーは実体を共有する

値を持つか、住所を持つか

a = 10 のような値型は、スタックの箱に数値そのものが入ります。だから b = a は中身をまるごとコピーした別の箱で、あとから b20 にしても a10 のまま。2つは最初から無関係です。

一方 new Box(99) でつくった実体はヒープに置かれ、住所(例:0x7f)がつきます。変数 box がスタックに持つのは値ではなく、その住所を指す地図(ポインタ/参照)です。alias = box地図をコピーしただけなので、実体は1つのまま2人が同じ場所を指します。だから alias.value = 77 とすると、同じ実体を見ている box.value77 に――これが「コピーしたのに連動する」の正体です。

用語ミニ辞書
スタック
関数の変数や値型をLIFOで積む高速な領域。サイズが決まった値そのものを置く。
ヒープ
実体(オブジェクトや配列)を置く領域。住所がつき、ポインタ経由で読み書きする。
ポインタ/参照
実体そのものではなく、その置き場所(住所)を指す値。コピーしても実体は増えない。
値型と参照型
代入で中身ごとコピーされるのが値型、住所だけコピーされ実体を共有するのが参照型。

まとめ

同じ = でも、値型は「中身のコピー」、参照型は「地図のコピー」。前者は独立し、後者は同じ実体を共有します。「コピーしたはずなのに片方を変えたら両方変わった」というバグの多くは、ここを取り違えたために起きます。図1をもう一度進めて、スタックの箱の中身が値か住所かを見分けられれば、もう迷いません。