プログラムコード、グローバル変数、定数グローバル変数は、いずれも静的なライフタイムを持ち、コンパイル時にサイズが分かっているため、static segment(静的領域)に格納されます。
mexploreが出力したアドレスを見ると、グローバル変数は比較的低いアドレス(16進数でおよそ0x60'0000や0x40'0000)にあり、ローカル変数は0x7fff'ffff'ffff(約 247)に近い高いアドレスにあります。動的に確保された文字データは、その中間、ただし静的領域に近い位置に格納されます。この配置には理由があります。二種類の領域を互いに干渉させずに拡張できるためです。特に automatic-lifetime segment(自動ライフタイム領域)は、スコープに入るローカル変数が増えると下方向へ拡張し、dynamic-lifetime segment(動的ライフタイム領域)は上方向へ拡張します。両者が衝突すると、コンピューターのメモリが不足します。
メモリ領域の分類#
コンピューターでプログラムを実行すると、memory layout(メモリレイアウト)は通常、複数の領域に分かれます。各領域は特定の種類のデータを格納します。主な領域は次のとおりです。
text segment(コード領域):
- 格納内容: プログラムの実行可能コード、つまりコンパイル後の機械語命令を格納します。通常は読み取り専用で、コードが誤って、または悪意を持って変更されることを防ぎます。
- 特徴: 多くのオペレーティングシステムは、読み取り専用かつ実行可能な領域として扱います。
data segment(データ領域):
- 格納内容: 初期化済みのグローバル変数と static variable(静的変数)を格納します。この領域はさらに二つに分けられます。
- initialized data segment(初期化済みデータ領域): コンパイル時に初期化されたグローバル変数と静的変数を格納します。
- BSS segment(BSS 領域、Block Started by Symbol): 未初期化のグローバル変数と静的変数を格納します。プログラムの開始時に内容は 0 に初期化されます。
- 特徴: データ領域は読み書き可能です。
- 格納内容: 初期化済みのグローバル変数と static variable(静的変数)を格納します。この領域はさらに二つに分けられます。
heap(ヒープ、dynamic-lifetime segment):
- 格納内容: 動的に確保されたメモリブロックを格納します。
malloc、calloc、reallocなどの関数は、実行時にヒープからメモリを確保します。ヒープのサイズは実行時に拡大・縮小できます。 - 特徴: ヒープ領域は通常、低いアドレスから高いアドレスへ拡張します。
- 格納内容: 動的に確保されたメモリブロックを格納します。
stack(スタック、automatic-lifetime segment):
- 格納内容: 関数のローカル変数、関数引数、戻りアドレスを格納します。関数が呼び出されると、関数のローカルデータを格納する stack frame(スタックフレーム)が作られます。関数呼び出しが終わると、そのスタックフレームは解放されます。
- 特徴: スタック領域は通常、高いアドレスから低いアドレスへ拡張します。スタックサイズには上限があり、深すぎる再帰呼び出しや大量のローカル変数によってスタックオーバーフローが起こることがあります。
rodata segment(読み取り専用データ領域):
- 格納内容: 文字列リテラルなどの読み取り専用データを格納します。通常はコンパイル時に決まり、実行時には変更されません。
- 特徴: この領域は通常、読み取り専用です。
call stack(コールスタック):
- 格納内容: 各スレッドの呼び出し情報、関数呼び出しの戻りアドレス、ローカル変数、関数引数を格納します。コールスタックはスタック領域と重なる概念です。
- 特徴: 再帰呼び出しや大量のローカル変数によってスタックオーバーフローが起こることがあります。
メモリレイアウトの模式図#
典型的なメモリレイアウトを、==高いアドレスから低いアドレスへ==並べると次のようになります。
+--------------------+
| スタック (Stack) |
+--------------------+
| ヒープ (Heap) |
| (動的確保領域) |
+--------------------+
| 未初期化データ領域 (BSS) |
+--------------------+
| 初期化済みデータ領域 (Data) |
+--------------------+
| 読み取り専用データ (Rodata) |
+--------------------+
| コード領域 (Text) |
+--------------------+
| その他のシステム領域 (Other) |
+--------------------+
C 言語では、変数は型とスコープに応じてプログラム内の異なるメモリ領域に配置されます。変数の種類ごとの格納場所は次のとおりです。
global variable(グローバル変数):
- 定義: 関数の外側で定義され、グローバルスコープを持つ変数です。プログラムの実行中はどこからでもアクセスできます。
- 格納場所:
- 初期化済みグローバル変数は、**data segment(データ領域)**の初期化済みデータ領域に格納されます。
- 未初期化グローバル変数は BSS segment(BSS 領域、Block Started by Symbol) に格納され、プログラム開始時に 0 へ初期化されます。
static variable(静的変数):
- 定義:
staticキーワードで修飾された変数です。グローバル変数にもローカル変数にもできますが、プログラムのライフタイム中に一度だけ確保され、値を保持します。 - 格納場所:
- 静的グローバル変数はグローバル変数と同様に、初期化済みならデータ領域、未初期化なら BSS 領域に格納されます。
- 静的ローカル変数はスコープが関数内に限られていても、ライフタイムはプログラムと同じです。そのためデータ領域または BSS 領域に格納されます。
- 定義:
constant variable(定数変数):
- 定義:
constキーワードで修飾され、宣言後に値を変更できない変数です。 - 格納場所:
- 定数グローバル変数は通常、**rodata segment(読み取り専用データ領域)**に格納されます。ただしローカル定数の場合は、コンパイラーの最適化によってスタックやレジスターに置かれることがあります。
- 定数ローカル変数は通常スタックに確保されますが、場合によってはコンパイラーによってレジスターへ最適化されます。
- 定義:
local variable(ローカル変数):
- 定義: 関数やブロック内で定義され、そのスコープ内だけで有効な変数です。
- 格納場所:
- 通常は stack(スタック) に格納されます。関数呼び出し時にスタック上の領域が確保され、関数が戻ると解放されます。
dynamically allocated memory(動的確保メモリ):
- 定義:
malloc、calloc、reallocなどで動的に確保するメモリです。サイズと個数は実行時に決まります。 - 格納場所:
- heap(ヒープ) に格納されます。ヒープメモリのライフタイムはプログラマーが管理するため、
freeで手動解放しなければメモリリークにつながります。
- heap(ヒープ) に格納されます。ヒープメモリのライフタイムはプログラマーが管理するため、
- 定義:
まとめ#
- text segment(コード領域): プログラムの実行可能コードを格納します。
- data segment(データ領域): 初期化済みのグローバル変数と静的変数を格納します。
- BSS segment(BSS 領域): 未初期化のグローバル変数と静的変数を格納し、プログラム開始時に 0 へ初期化します。
- rodata segment(読み取り専用データ領域): 定数データと文字列リテラルを格納します。
- stack(スタック): ローカル変数、関数引数、戻りアドレスを格納します。
- heap(ヒープ): 動的に確保されたメモリを格納します。
これらのメモリ領域と役割を理解することは、効率的で安全なプログラミングに重要です。特に、動的メモリ管理、グローバル状態、並行処理を扱う場合に役立ちます。

