ホーム第3章: プログラムとメモリ
第3章 3節

スタック領域とヒープ領域

プログラムを実行するとき、OSはそのプログラム専用にメインメモリ(RAM)の一部を割り当てます。このメモリ空間は目的に応じていくつかの領域に分かれており、中でもデータ管理の方法が根本的に異なる「スタック領域」と「ヒープ領域」が重要です。

1. メモリ空間の全体像

プログラムに割り当てられるメモリ空間には、静的なデータ(機械語コードやグローバル変数)を置く領域のほかに、実行中に動的に変化するデータを保管する2つの領域があります。スタック(Stack)領域ヒープ(Heap)領域です。

テキスト領域(コード)/ 静的データ スタック領域 ヒープ領域 高アドレス ➔ 低へ成長 低アドレス ➔ 高へ成長 空き領域(共有)
図 3-4:仮想メモリ内におけるスタック領域とヒープ領域の対向配置図

多くのシステムでは、限られたメモリ空間を無駄にしないよう、スタック領域を高アドレス側に置いて下方向へ、ヒープ領域を低アドレス側に置いて上方向へ伸ばす対向配置をとります。

2. スタック領域:整理整頓された高速領域

スタック領域は、名前の通り「お皿を積み重ねる(Stack)」ようにデータを管理する領域です。 主に、関数呼び出し時に必要となる一時的な情報(ローカル変数、引数、戻りアドレス)を格納します。

関数が呼び出されると、その関数の変数などをまとめたスタックフレームが一番上に積まれます。関数が終了するとそのフレームは自動的に取り除かれ(ポップされ)、メモリも瞬時に解放されます。

スタック領域の特徴
  • 超高速: 確保と解放が「一番上に積む・取る」だけなので、極めて高速です。
  • 自動管理: 関数の開始・終了に連動してコンパイラが確保・解放の命令を組み込むため、プログラマが解放を忘れる心配がありません。
  • 容量が小さい: 通常は数MB程度しか割り当てられず、大きな配列や極端に深い再帰呼び出しを行うと、領域を使い果たしてスタックオーバーフロー(Stack Overflow)エラーを引き起こします。

3. ヒープ領域:自由で広大だが管理が必要な領域

ヒープ(Heap)とは「ごちゃ混ぜの山」という意味です。 実行中に必要なサイズが事前にわからず、動的に確保・解放したいデータ(オブジェクト、大規模な配列、ユーザー入力データなど)を保存するために使います。

ヒープ領域では、スタックのように順番通りに積み重ねるルールはありません。広大なメモリの空いている場所を探してデータを配置し、不要になったらそこを解放します。

ヒープ領域の特徴
  • 自由度が高い: サイズを実行中に自由に決められ、確保したデータは明示的に解放するまでメモリ上に残り続けます。
  • 速度が遅い: 空き領域を探して割り当てるため、スタックに比べて確保・解放のオーバーヘッドが大きくなります。
  • 手動管理またはGC: C言語などでは手動で解放する必要があります。PythonやGo、JavaScriptなどではガベージコレクタ(GC)が不要なメモリを自動回収しますが、GC実行中に一時的な遅延が発生することがあります。
  • メモリリークの危険: 不要なメモリの解放を忘れると、稼働中にヒープ領域を食いつぶし、最終的にOS全体のメモリ不足や強制終了を引き起こします。
SIMULATOR

スタック vs ヒープ メモリ仮想アロケーター

関数呼び出しによる「スタック」の自動積載と、`malloc`/`free`による「ヒープ」の手動確保・解放をシミュレートします。メモリリークや断片化(フラグメンテーション)が起きる仕組みを体験しましょう。

スタック操作 (LIFO)

関数が呼ばれると自動で積まれ、終わると自動で消滅します。

ヒープ操作 (手動管理)

任意のサイズで動的に確保し、使い終わったら明示的に解放します。

確保済みブロックの解放:
確保されているブロックはありません
高アドレス (Stack開始)
スタック領域 (Stack)
未使用領域 (空きメモリ)
ヒープ領域 (Heap)
低アドレス (Heap開始 / 静的領域)

4. 2つの領域の比較まとめ

スタックとヒープは適材適所で使い分けられています。

比較項目 スタック領域 ヒープ領域
主な用途 関数の実行情報、ローカル変数、引数 動的なオブジェクト、配列、大容量データ
データ構造 LIFO (Last-In First-Out) 順不同 (自由配置)
サイズ制限 小さい (通常 数MB程度) 非常に大きい (物理メモリの許す限り)
アクセス速度 極めて高速 比較的遅い
寿命の管理 自動(関数終了時に消失) 手動またはGC(明示的に解放されるまで存在)

次のセクションでは、メモリの「番地」を直接扱う低レベルかつ強力な概念「ポインタ」について学びます。

現実世界と繋ぐ:アプリのクラッシュ原因?「メモリリーク」と「スタックオーバーフロー」

プログラムが突然フリーズしたり強制終了したりするバグの多くは、このメモリ管理の仕組みと密接に関係しています。

  • メモリリーク (Memory Leak): ヒープ領域を `malloc` などで確保したものの、使い終わった後に `free` による解放を忘れてしまうバグです。PCを再起動しないと徐々に動作が重くなるブラウザやゲームは、多くの場合メモリリークが蓄積して、OS全体からメモリを奪ってしまっている状態です。
  • スタックオーバーフロー (Stack Overflow): スタック領域は容量が小さいため、再帰関数(自分自身を呼び出す関数)の終了条件を書き忘れたり、画像データのような巨大な配列をローカル変数に配置しようとすると、あっという間にスタックの壁を突き破ってプログラムが即座に強制終了(クラッシュ)します。

今日の主要なプログラミング言語(JavaScript, Python, Swiftなど)では、不要になったヒープメモリを自動で掃除する仕組み(ガベージコレクションやARC)が導入されていますが、依然として「メモリ消費量を低く保つ」ことは、開発者にとって重要なスキルであり続けています。