メモリレイアウトまとめ|メモリレイアウトからポインタまでtext・data・bss・heap・stackを体系的に理解する

目次

メモリ構造をまとめて理解したい

初心者さん

先輩、メモリ関連の勉強をしたいのですがどこから勉強すればよいか分かりません!

エンジニアくん

そうだね。このページではメモリ構造の全体像と、メモリ構造解説シリーズの紹介をするよ。

C言語を学んでいると、

  • text領域とは何か
  • data領域とbss領域は何が違うのか
  • stackとheapはどう使い分けるのか
  • static変数はどこに置かれるのか

といった疑問が次々に出てきます。

これらは個別に理解することも大切ですが、実際には 1つのメモリ構造としてつながっている知識 です。
特に組み込み開発では、メモリの使われ方を正しく理解していないと、不具合の原因や設計判断を見誤りやすくなります。

この記事では、C言語のメモリ構造を 全体像から整理しつつ、各テーマの詳細記事にも進めるようにまとめ ました。
まずは全体をつかみ、そのあと気になる領域を個別に深掘りしていくのがおすすめです。


この記事は「メモリ構造解説シリーズ」の入口です

このページは、メモリ関連記事をまとめた ハブ記事 です。
細かい説明は個別記事で行い、このページでは 全体像と学ぶ順番 を整理します。

おすすめの読み方は次の通りです。

  1. まず全体像をつかむ
  2. data / bss の違いを理解する
  3. stack と heap の違いを押さえる
  4. static変数やスタートアップコードで理解を深める

C言語のメモリ領域の全体像

C言語のプログラムでは、メモリは役割ごとにいくつかの領域に分かれています。
代表的なのが次の5つです。

領域主な用途
text領域プログラムの命令コード
data領域初期値ありのグローバル変数 / static変数
bss領域初期値なしのグローバル変数 / static変数
heap領域malloc などで確保する動的メモリ
stack領域関数呼び出し、ローカル変数、自動変数

まずはこの全体像を押さえることが大切です。
個別の知識だけを覚えても、メモリ全体のつながりが見えていないと実務で活かしにくくなります。

メモリ領域全体を最初に整理したい方は、こちらの記事から読むと流れがつかみやすいです。

関連記事


ROM・FLASH・RAMの関係

組み込みシステムでは、メモリは大きく ROM(FLASH)とRAM に分かれます。

FLASH(ROM)
 ├ プログラム(text領域)
 └ 初期値付き変数
RAM
 ├ data領域
 ├ bss領域
 ├ heap
 └ stack

FLASHは電源を切っても内容が消えない不揮発メモリで、プログラムや初期値データを保存します。
一方、RAMはプログラム実行中に使われる作業メモリで、電源を切ると内容が消えます。

例えば次のコードを考えてみます。

int g = 10;

この変数の初期値 10 は、プログラムの中では FLASHに保存されています。

そしてマイコンが起動すると、スタートアップコードによって

FLASH → RAM(data領域)

へコピーされます。

つまり実行中の変数はRAMに存在しますが、その初期値はFLASHに保存されているのです。

ROM・FLASH・RAMの違いについては、こちらの記事で詳しく解説しています。

関連記事

RAMの種類(DRAMとSRAM)

RAMにはいくつか種類があり、代表的なのが DRAMSRAM です。
どちらもRAMですが、仕組みや用途が異なります。

・DRAM:大容量だが遅い(外部メモリ向け)
・SRAM:高速だが小容量(マイコン内部RAM向け)

組み込み開発では、この特性を理解して使い分けることが重要です。

詳しくはこちらの記事で解説しています。

関連記事

text領域とは

text領域には、コンパイルされたプログラムの命令コードが配置されます。
いわゆる「実行する中身」が置かれる場所です。

普段は data や stack ほど意識しないかもしれませんが、
「コードもメモリ上に存在している」という視点を持つと、メモリマップ全体が理解しやすくなります。

text領域については、まずは全体解説記事の中でイメージを押さえれば十分です。
必要であれば今後、text領域だけを深掘りした個別記事を追加してもよいと思います。

関連記事


data領域とbss領域の違い

C言語のメモリ構造で、最初につまずきやすいのが data領域とbss領域の違い です。

どちらも主に

  • グローバル変数
  • static変数

が配置される領域ですが、違いは 初期値の有無 です。

  • 初期値あり → data領域
  • 初期値なし → bss領域

この違いは単なる暗記で終わりがちですが、実際には

  • なぜ領域を分けるのか
  • 起動時にどう初期化されるのか
  • static変数とどう関係するのか

までつながっています。

この部分を理解すると、組み込み開発でよく出てくる「RAM使用量」や「初期化処理」の意味も見えやすくなります。

関連記事


スタートアップコードと初期化処理

C言語のプログラムは、電源投入やリセット直後にいきなり main() から始まるわけではありません。
その前に、スタートアップコードによって必要な初期化が行われます。

代表的なのは次のような処理です。

  • data領域の初期値をROMからRAMへコピーする
  • bss領域を0で初期化する
  • 実行に必要な準備をしてから main() に入る

この流れを理解すると、data領域とbss領域が分かれている理由も自然に見えてきます。
組み込み開発ではかなり実務的な知識です。

関連記事


stack領域とは

stack領域は、関数呼び出しやローカル変数で使われる領域です。
C言語を学ぶ中で、かなり重要な領域の1つです。

stack領域の特徴としては、

  • 関数の呼び出しごとに使用される
  • 自動変数が配置される
  • 関数を抜けると基本的に不要になる
  • サイズ不足でスタックオーバーフローの原因になることがある

といった点があります。

特に組み込みではRAMが小さいことも多く、stack使用量を意識することが重要です。
ローカル変数を大きく取りすぎると、思わぬ不具合につながることがあります。

また、関数が呼び出されると、スタック上には**スタックフレーム(Stack Frame)**と呼ばれる領域が作られます。
スタックフレームには、ローカル変数や戻りアドレスなどが保存されます。

関連記事


heap領域とは

heap領域は、malloc などで動的に確保するメモリのための領域です。
必要なときに必要な分だけ確保できるのが利点ですが、その分だけ管理が難しくなります。

たとえば、

  • 解放忘れによるメモリリーク
  • 確保失敗時の考慮
  • 断片化
  • 実行時間のばらつき

といった問題が起こりやすくなります。

そのため、特に組み込み開発では malloc が避けられる場面も少なくありません。
「使えるけれど、設計上は慎重に扱うべきもの」という理解が実務的です。

関連記事


static変数とは

static変数は、メモリ構造を理解するうえでかなり重要です。
関数内で宣言しても値を保持し続けるため、初学者には少し不思議に見えるかもしれません。

ポイントは、

  • スコープはローカルにもできる
  • しかし寿命はプログラム終了まで続く
  • 配置されるのは stack ではなく data / bss 領域

という点です。

つまり static変数は、
見た目はローカル変数っぽいのに、メモリ上は静的領域に置かれる というのが面白いところです。

data領域・bss領域の理解が浅いと、static変数も曖昧になりやすいので、合わせて読むのがおすすめです。

関連記事


ポインタとは

ポインタは、メモリアドレスを扱うための変数です。
C言語では、メモリを直接扱うための基本的な仕組みとして使われます。

ポインタを使うことで、

  • 配列の先頭アドレスを扱う
  • 関数にデータを参照渡しする
  • 動的メモリ(malloc)を扱う

といったことが可能になります。

一方で、ポインタはメモリを直接操作できるため、

  • NULLポインタ参照
  • ダングリングポインタ
  • 不正なメモリアクセス

といったバグの原因にもなりやすい特徴があります。

C言語では、メモリ構造とポインタの関係を理解することが非常に重要です。

関連記事

C言語の配列とポインタの違いとは?メモリの視点でわかりやすく解説

メモリマップとは?

組み込み開発では、プログラムや変数が
ROMやRAMのどこに配置されるかがあらかじめ決まっています。

この配置を示したものが メモリマップ です。

例えば、典型的なメモリマップは次のようになります。

ROM
・text(プログラムコード)
・rodata(constデータ)
・data(初期値)

RAM
・data(初期値あり変数)
・bss(未初期化変数)
・heap(動的確保)
・stack(関数呼び出し)

この配置に基づいて、スタートアップコードが
dataコピーやbss初期化を行います。

詳しくはこちらの記事で解説しています。

👉 メモリマップとは?組み込みC言語のROM・RAMメモリ配置をわかりやすく解説

リンカスクリプトとは?

メモリマップで説明した配置は、
自動的に決まっているわけではありません。

実はこの配置は リンカスクリプト によって決められています。

リンカスクリプトでは、例えば次のように指定します。

・text を ROM に配置
・data を RAM に配置
・bss を RAM に配置
・stack の位置
・heap の位置

リンカはこの設定に従って、
プログラムや変数をメモリに配置します。

つまり

メモリマップ
= リンカスクリプトの結果

という関係になります。

詳しくはこちらの記事で解説しています。

👉 リンカスクリプトとは?組み込みC言語のメモリ配置の仕組みをわかりやすく解説

どの記事から読めばよいか

「どこから読めばいいかわからない」という方向けに、読む順番をまとめると次の流れがおすすめです。

まず全体像を知りたい方

data領域とbss領域がよくわからない方

stackとheapの違いを理解したい方

static変数の配置を理解したい方

ポインタとの関係について理解したい方

まとめ

C言語のメモリ構造は、

  • text領域
  • data領域
  • bss領域
  • heap領域
  • stack領域

といった各領域の役割を個別に理解することも大切ですが、
全体としてどうつながっているかを理解すること がもっと重要です。

このページでは、メモリ関連記事をまとめて整理しました。
まずは全体像をつかみ、そのあと気になるテーマを個別記事で深掘りしてみてください。

今後このシリーズでは、たとえば次のようなテーマを追加していくと、さらに理解が深まります。

  • スタックオーバーフローとは何か
  • スタックとヒープの違い
  • メモリリークとは何か
  • グローバル変数の問題点
  • リンカスクリプトとメモリ配置の関係

メモリ構造は、C言語や組み込み開発を学ぶうえで避けて通れない基礎です。
シリーズでまとめて理解していきましょう。

この記事が参考になった方へ

技術に関するご相談・開発・自動化ツール作成・記事執筆などのご依頼も承っています。

小さなご相談からでもお気軽にご連絡ください。

お問い合わせはこちら

よかったらシェアしてね!
  • URLをコピーしました!
  • URLをコピーしました!

この記事を書いた人

コメント

コメントする


目次