プロセスが開始されると、プロセスは独自の仮想アドレス空間を取得します。仮想アドレス空間のサイズは、オペレーティング システムによって異なります。一般に、32 ビット プロセスは 4 GiB (4 ギガ バイナリ) アドレスを取得し、64 ビット プロセスは 18 EiB (18 エクサ バイナリ) アドレスを取得します。
定義上、そこにマップされていないものにはアドレスがないため、仮想アドレス空間にマップされていないものには決してアクセスできません。現在何にもマップされていない仮想アドレス空間の領域にアクセスしようとすると、segfault 例外が発生します。
すべてのアドレス空間が常に何かにマップされるわけではありません。また、すべてがマップされるわけではありません (どの程度マップされるかは、プロセッサとオペレーティング システムによって異なります)。現在の世代の Intel プロセッサでは、最大 256 TiB のアドレス空間をマップできます。オペレーティング システムによってさらに制限される可能性があることに注意してください。たとえば、32 ビット プロセス (最大 4 GiB アドレスを持つ) の場合、Windows は既定でシステム用に 2 GiB、アプリケーション用に 2 GiB を予約します (ただし、システム用に 1 GiB、アプリケーション用に 3 GiB にする方法があります)。
使用されているアドレス空間の量とマップされている量は、アプリケーションの実行中に変化します。オペレーティング システム固有のツールを使用すると、実行中のアプリケーションに現在割り当てられているメモリと仮想アドレス空間を監視できます。
コード セクション、データ セクション、BSS などは、リンカーによって作成される実行可能ファイルのさまざまな領域を指す用語です。一般に、コードは、静的に割り当てられているが変更可能なデータとは別の静的な不変データとは別のものです。スタックとヒープは、上記のすべてとは別のものです。それらのサイズは、コンパイラとリンカによって計算されます。各バイナリ ファイルには独自のセクションがあるため、動的にリンクされたライブラリはアドレス空間に個別にマップされ、それぞれ独自のセクションがどこかにマップされることに注意してください。ただし、ヒープとスタックはバイナリ イメージの一部ではありません。通常、プロセスごとに 1 つのスタックと 1 つのヒープしかありません。
スタック (少なくとも初期スタック) のサイズは通常固定されています。コンパイラやリンカーには通常、実行時に必要なスタックのサイズを設定するために使用できるいくつかのフラグがあります。スタックは一般に「後方に成長」します。これは、プロセッサのスタック命令がそのように機能するためです。スタックを一方向に成長させ、残りを他の方向に成長させると、両方を無制限にしたいが、それぞれがどれだけ成長できるかわからない状況で、メモリを整理しやすくなります。
一般に、ヒープとは、プロセスの開始時に事前に割り当てられていないものを指します。最下位レベルには、ヒープ管理に関連するいくつかの論理操作があります (ここで説明するように、すべてのオペレーティング システムですべてが実装されているわけではありません)。
アドレス空間は固定されていますが、一部の OS は、現在プロセスによって再利用されている部分を追跡しています。そうでない場合でも、プロセス自体がそれを追跡する必要があります。したがって、最も低いレベルの操作は、アドレス空間の特定の領域が使用されることを実際に決定することです。
2 番目の低レベル操作は、その領域を何かにマップするよう OS に指示することです。これは、一般的に次のことができます。
スワップできないメモリ
スワップ可能で、システム スワップ ファイルにマップされているメモリ
スワップ可能で、他のファイルにマップされているメモリ
スワップ可能で、読み取り専用モードで他のファイルにマップされているメモリ
別の仮想アドレス領域がマップされているのと同じマッピング
別の仮想アドレス領域がマップされているのと同じマッピングですが、読み取り専用モードです
別の仮想アドレス領域がマップされているのと同じマッピングですが、コピーされたデータがデフォルトのスワップ ファイルにマップされたコピー オン ライト モードです。
他にも忘れた組み合わせがあるかもしれませんが、主なものは以上です。
もちろん、使用される合計スペースは、定義方法によって異なります。現在使用されている RAM は、現在マップされているアドレス空間とは異なります。しかし、上で書いたように、オペレーティング システムに依存するツールを使用すると、現在何が起こっているかを知ることができます。