仮想アドレス領域

メモリ ロケーションの読み取りまたは書き込みを行うときに、プロセッサは仮想アドレスを使います。読み取りまたは書き込み操作の一環としてプロセッサは、仮想アドレスから物理アドレスへの変換を行います。仮想アドレスを介したメモリ アクセスには次の 3 つの利点があります。

  • プログラムでは、物理メモリでは連続していない大規模なメモリ バッファーに対し、仮想アドレスの連続した範囲を利用してアクセスできます。

  • プログラムでは、仮想アドレスの範囲を利用して、実際に物理メモリで提供されるサイズを超えるメモリ バッファーにアクセスすることができます。物理メモリの容量が少なくなってくると、メモリ マネージャーが物理メモリのページ (サイズは通常 4 KB) をディスク ファイルに保存します。データまたはコードのページが、必要に応じて物理メモリとディスクの間を移動します。

  • 個々のプロセスが使う仮想アドレスはそれぞれ独立しています。あるプロセス中のコードが、別のプロセスまたはオペレーティング システムで使われている物理メモリを変更することはできません。

あるプロセスで利用できる仮想アドレスの範囲は、そのプロセスの仮想アドレス領域と呼ばれます。個々のユーザー モード プロセスには独自のプライベート仮想アドレス領域が割り当てられます。 32 ビット プロセスの仮想アドレス領域は通常、0x00000000 ~ 0x7FFFFFFF の 2 GB 分です。64 ビット プロセスの仮想アドレス領域は、0x000'00000000 ~ 0x7FF'FFFFFFFF の 8 TB 分です。仮想アドレスの範囲は、仮想メモリの範囲と呼ばれることもあります。

下図は、仮想アドレス領域の主な特徴を表したものです。

2 つのプロセスに対する仮想アドレス領域

図は、Notepad.exe、MyApp.exe という 2 つの 64 ビット プロセスに対する仮想アドレス領域を示しています。各プロセスに 0x000'00000000 ~ 0x7FF'FFFFFFFF の範囲の独自の仮想アドレス領域がそれぞれ割り当てられます。影が付いた部分は、仮想メモリまたは物理メモリの 1 ページ (サイズ 4 KB) に相当します。Notepad プロセスでは、0x7F7'93950000 から始まる 3 ページ分の連続した仮想アドレスを使います。ただし、この連続した 3 ページの仮想アドレスは、物理メモリではそれぞれ連続しないページにマッピングされます。また両プロセスとも、0x7F7'93950000 から開始する仮想メモリのページを使っていますが、各仮想ページは、物理メモリでは別のページにマッピングされます。

ユーザー空間とシステム空間

Notepad.exe や MyApp.exe などのプロセスはユーザー モードで実行されます。オペレーティング システムのコア コンポーネントや多くのドライバーは、より特権レベルの高いカーネル モードで実行されます。プロセッサ モードについて詳しくは、「ユーザー モードとカーネル モード」をご覧ください。各ユーザー モード プロセスには、それぞれ個別のプライベート仮想アドレス領域が割り当てられますが、カーネル モードで実行されるコードはすべて、システム空間と呼ばれる単一の仮想アドレス領域を共有します。現在のユーザー モード プロセスに対する仮想アドレス領域は、ユーザー空間と呼ばれます。

32 ビット Windows では、仮想アドレス領域全体の容量は 2^32 バイト (4 GB) になります。通常、下位の 2 GB 分がユーザー空間に、上位の 2 GB 分がシステム空間にそれぞれ割り当てられます。

システム空間の図

32 ビット Windows の場合は、2 GB を超える空間をユーザー空間として割り当てるようにブート時に指定することができます。このように指定すると、システム空間に割り当てられる仮想アドレスの容量が少なくなります。ユーザー空間のサイズは、3 GB まで拡張することができます。この場合、システム空間として利用できる容量はわずか 1 GB になります。ユーザー空間のサイズを増やすには、BCDEdit /set increaseuserva を使います。

64 ビット Windows の場合、仮想アドレス領域の容量は理論上、2^64 バイト (16 エクサバイト) になりますが、実際に使うのは 16 エクサバイトの範囲のうちわずかにすぎません。ユーザー空間には、0x000'00000000 ~ 0x7FF'FFFFFFFF の 8 TB 分が使われます。システム空間には 0xFFFF0800'00000000 ~ 0xFFFFFFFF'FFFFFFFF の 248 TB 分が使われます。

ページ プールと非ページ プールの図

ユーザー モードで実行されるコードは、ユーザー空間にアクセスできますが、システム空間にはアクセスできません。この制限により、保護されたオペレーティング システムのデータ構造がユーザー モードのコードによって読み取られたり、変更されたりすることがなくなります。カーネル モードで実行されるコードは、ユーザー空間とシステム空間の両方にアクセスできます。つまり、カーネル モードで実行されるコードからは、システム空間と、現在実行されているユーザー モード プロセスの仮想アドレス領域にアクセスできます。

したがって、カーネル モードで実行するドライバーでは、ユーザー空間でのアドレスに直接読み取りと書き込みができることに十分に配慮する必要があります。その理由について、次のシナリオに基づいて説明します。

  1. ユーザー モード プログラムから、特定のデバイスにある一部のデータの読み取り要求が出されます。このプログラムにより、データを受け取るバッファーの開始アドレスが指定されます。

  2. カーネル モードで実行するデバイス ドライバー ルーチンが読み取り動作を開始し、呼び出し元に制御を返します。

  3. 後で、デバイスは、その時点で実行されている任意のスレッドに割り込んで、読み取り動作が完了したことを伝えます。 割り込みは、ある任意のプロセスに属している、この任意のスレッドの実行を担当しているカーネル モード ドライバー ルーチンによって処理されます。

  4. この時点で、手順 1 でユーザー モード プログラムから指定される開始アドレスに対し、ドライバーがデータを書き込まないようにします。このアドレスは、要求側プロセスの仮想アドレス領域に置かれるため、現在のプロセスのアドレスと競合することはまずありません。

ページ プールと非ページ プール

ユーザー空間では、必要に応じてすべての物理メモリ ページをディスク ファイルにページ アウトできます。システム空間の物理ページには、ページ アウトできるものとできないものがあります。システム空間では、ページ プールと非ページ プールという 2 つの領域にメモリを動的に割り当てます。64 ビット Windows のページ プールは、0xFFFFA800'00000000 ~ 0xFFFFA81F'FFFFFFFF の仮想アドレスの 128 GB 分です。非ページ プールは、0xFFFFAC00'00000000 ~ 0xFFFFAC1F'FFFFFFFF の仮想アドレスの 128 GB 分です。

ページ プールに割り当てられたメモリは、必要に応じてディスク ファイルにページ アウトできます。非ページ プールに割り当てられたメモリは、ディスク ファイルにページ アウトすることはできません。

ページ プールと非ページ プールのメモリ割り当ての比較図

関連トピック

ユーザー モードとカーネル モード