64ビット(Win64)での仮想アドレス空間

64ビットCPUでは当然のことながら、32ビットCPUと比べてはるかに広大な仮想アドレス空間を扱うことが出来ます。簡単なプログラムで、この広大なアドレス空間を堪能してみましょう。

(本記事の初稿は2005年です。64ビットCPUが普及した現在でも有用な内容と思われるので、そのままの内容で公開します。)

■CPUとOS上でのアドレス空間
本題に入る前に、アドレス空間についてまとめておきます。64-bitのプロセス(Long mode(IA32e mode))で扱える物理アドレスと仮想アドレスは以下のようになります。

  物理アドレス空間:52-bit(1PB)。ただし現時点では40-bit(1TB)に制限されている。
  仮想アドレス空間:48-bit(256TB)

  物理アドレス空間:35-bit(32GB)もしくは40-bit(1TB)
  仮想アドレス空間(1つのプロセス全体(USER+SYSTEM)):44-bit(16TB)
  仮想アドレス空間(1つのプロセス(USERのみ)):43-bit(8TB)

仮想アドレス空間が64-bitとなっていませんが、これらは実装上のサイズです。Win64ではポインタはすべて64-bitです。(この場合上位16ビット(bits 63-48)は、有効なビット(bits 47-0)の最上位ビット(bit 47, MSB(Most Significant Bit)と呼ぶ)の値で埋めておきます。これをCanonical Address Formと呼びます。ポインタとして有効なのは下位48ビットのみです。)比較用に32-bit環境についても記します。

  物理アドレス空間:32-bit(4GB)。PAE(Physical Address Extension)使用時は36-bit(64GB)。
  仮想アドレス空間:32-bit(4GB)

  物理アドレス空間:32-bit(4GB)。boot.iniに/PAE指定時は36-bit(64GB)(※1)
  仮想アドレス空間(1つのプロセス全体(USER+SYSTEM)):32-bit(4GB)
  仮想アドレス空間(1つのプロセス(USERのみ)):31-bit(2GB)。boot.iniに/3GB指定時は3GB利用することも可能。(※2)

  ※1 Physical Address Extension(PAE):
    32-bitのCPUで36-bitの物理メモリを扱うための(CPU側の)仕組み。
    より大量の物理メモリを扱えるので、スワップアウト回数軽減などの効果を期待できる。
    ユーザープロセスには直接は影響しない。(仮想アドレス空間(USER)が広くなるわけではない。)
  ※2 4GT RAM Tuning:
    プロセスに(2GBでなく)3GBの仮想アドレス空間を与えるための(Windows側の)仕組み。
  ※3 Address Windowing Extensions(AWE):
    4GBを超える大量のメモリを1つのプロセスで扱うための(Windows側の)仕組み。(APIが提供される。)
    仮想アドレス空間(USER)が広くなるわけではない。仮想アドレス空間内の領域を通して、
    ページを切り替えながらメモリを読み書きする。
    (MS-DOS全盛時代に一世を風靡したEMS(Extend Memory Specification)に似ている。
    EMM386が懐かしい...)

■32-bitと64-bitで比較
さっそくプログラミングして試してみます。やることは2つです。
まずGlobalMemoryStatus()を用いて、プロセス内で使える(メモリを割り当ててもらえる)仮想アドレス空間の空きサイズを調べます。次に、サイズを増やしながら、VirtualAlloc()とVirtualFree()を用いてメモリの確保と解放を繰り返し、これをメモリ確保に失敗するまで繰り返し、果たしてどれだけのメモリを一括で確保できるのかを調べます。どれだけの仮想アドレス空間を一括で確保できるのかを調べるのが目的なのでメモリ確保の際にコミット(物理メモリもしくはページングファイルの割り当て)はせずに、予約するだけにします。

#include <windows.h>
#include <stdio.h>
#include <tchar.h>

#define MEGA (1024*1024)
#define GIGA (1024*1024*1024)

void main(void){
MEMORYSTATUS memstat;
SIZE_T mem_size, inc_size;
DWORD  flAllocationType;
DWORD  flProtect;
DWORD  dwFreeType;
LPVOID baseadr, baseadr2;

// GlobalMemoryStatus()で仮想アドレス空間の空きを調査
memstat.dwLength=sizeof(MEMORYSTATUS);
GlobalMemoryStatus(&memstat);
#ifndef _WIN64 // for Win32
_tprintf(TEXT("[Win32]Available virtual address space is %u MB.\n"), memstat.dwAvailVirtual/MEGA);
#else          // for Win64
_tprintf(TEXT("[Win64]Available virtual address space is %I64u GB.\n"), memstat.dwAvailVirtual/GIGA);
#endif

// サイズを増やしながら、メモリの予約・解放を繰り返す
#ifndef _WIN64   // for Win32
 mem_size=MEGA;  // 初期値は1MB
 inc_size=MEGA;  // IMBずつ増やす
#else            // for Win64
 mem_size=GIGA;  // 初期値は1GB
 inc_size=GIGA;  // 1GBずつ増やす
#endif
while(1) {
  flAllocationType=MEM_RESERVE;
  flProtect=PAGE_READWRITE;
  baseadr=VirtualAlloc(NULL,mem_size,flAllocationType,flProtect);
  if(baseadr!=NULL) {
    baseadr2=baseadr;
    dwFreeType=MEM_RELEASE;
    VirtualFree(baseadr, 0, dwFreeType);
    mem_size+=inc_size;
  } else {
    mem_size-=inc_size;
    break;
  }
} // END of while()
#ifndef _WIN64 // for Win32
_tprintf(TEXT("[Win32]Lump reservation of %u MB is OK. Address is %p.\n"), mem_size/MEGA, baseadr2);
#else          // for Win64
_tprintf(TEXT("[Win64]Lump reservation of %I64u GB is OK. Address is %p.\n"), mem_size/GIGA, baseadr2);
#endif



}

まずWindowsXP SP2で試してみます。

D:\>largemem
[Win32]Available virtual address space is 2041 MB.
[Win32]Lump reservation of 1987 MB is OK. Address is 00480000.

D:\>

次に、x64版WindowsXP(Ver.1218, Build 3790)で試してみます。(64ビットの方は完了するまで時間がかかります。)

D:\>largemem
[Win32]Available virtual address space is 2036 MB.
[Win32]Lump reservation of 1910 MB is OK. Address is 005B0000.

D:\>

D:\>largemem
[Win64]Available virtual address space is 8191 GB.
[Win64]Lump reservation of 1901 GB is OK. Address is 000000007FFF0000.

D:\>

32ビットの方はどちらも2GB弱確保できています。64ビットの方は一括では8TB弱確保できず2TB弱しか確保できていませんが、それでも32ビットの1000倍弱もあります。本当、広大です。AWEよりもこちらの方がお手軽です。(一括では8TB弱確保できなくても、より小さなサイズで複数回のメモリ確保をすることで、トータル8TB弱のメモリ確保ができるはず。)

■/LARGEADDRESSAWAREを付けて比較
32ビット用をビルドする際、リンカで/LARGEADDRESSAWAREオプションを指定すると、おもしろいことが起こります。
こうやってビルドしたものをまずWindowsXP SP2で実行します。

D:\>largemem
[Win32]Available virtual address space is 2041 MB.
[Win32]Lump reservation of 1987 MB is OK. Address is 00480000.

D:\>

/LARGEADDRESSAWAREオプションなしでビルドしたものと同じ結果です。一応、4GT RAM TuningなWindowsXP SP2(boot.iniに/3GBオプションを付加)でも試してみます。

D:\>largemem
[Win32]Available virtual address space is 3065 MB.
[Win32]Lump reservation of 1987 MB is OK. Address is 00480000.

D:\>

当然ですが、仮想アドレス空間が3GB弱に拡大しています。いよいよ、x64版WindowsXP(Ver.1218, Build 3790)で試してみます。

D:\>largemem
[Win32]Available virtual address space is 4084 MB.
[Win32]Lump reservation of 2047 MB is OK. Address is 7FFF0000.

D:\>

なんと32ビットのプロセスなのに、4GB弱の仮想アドレス空間が使えるようになりました。(一括で確保できるサイズはほぼ2GBきっかりで60MB程度増えただけだが。)それだけではありません。アドレスにもご注目ください。0~4GBの仮想アドレス空間の上位2GB(アドレス(番地)が2GB~4GB)に確保できています。この領域は32-bit版Windowsではシステムが予約している領域で、通常は使えません。

32ビットのアプリケーションも/LARGEADDRESSAWAREオプションをつけてリンクしてWOW64上で実行すれば、64-bit版Windowsのメリットを享受できるわけです。4GT RAM Tuningよりもお手軽かつ広いです。

■仮想アドレス空間の使用状況
ついでなので仮想アドレス空間の使用状況を一覧表示するプログラムを作ります。目的は2つあります。1つ目はアドレス空間のどの辺りに大量の未使用エリア(MEM_FREEなエリア)があるのかを調べること、2つ目はシステムが予約していてアクセスできない領域を調べることです。

#include <windows.h>
#include <stdio.h>
#include <string.h>
#include <tchar.h>

void main(void){
LPBYTE baseadr=0x0;
MEMORY_BASIC_INFORMATION mbi;
TCHAR message[256];
TCHAR bar[32];


_tprintf(TEXT("Address  Size(bytes)  Status\n"));
while(1){
 if(VirtualQuery(baseadr, &mbi, sizeof(mbi))) {
   #ifndef _WIN64 // for Win32
   _stprintf(message, TEXT("%p %08lx"), mbi.BaseAddress, mbi.RegionSize);
   #else          // for Win64
   _stprintf(message, TEXT("%p %016I64lx"), mbi.BaseAddress, mbi.RegionSize);
   #endif
   //
   if(mbi.State&MEM_FREE){ // MEM_FREE
    _tcscat(message, TEXT(" MEM_FREE"));
   } else {                // MEM_COMMIT or MEM_RESERVE
    if(mbi.State&MEM_COMMIT)               _tcscat(message, TEXT(" MEM_COMMIT"));
    if(mbi.State&MEM_RESERVE)              _tcscat(message, TEXT(" MEM_RESERVE"));
    if(mbi.Protect&PAGE_EXECUTE)           _tcscat(message, TEXT(" PAGE_EXECUTE"));
    if(mbi.Protect&PAGE_EXECUTE_READ)      _tcscat(message, TEXT(" PAGE_EXECUTE_READ"));
    if(mbi.Protect&PAGE_EXECUTE_READWRITE) _tcscat(message, TEXT(" PAGE_EXECUTE_READWRITE"));
    if(mbi.Protect&PAGE_EXECUTE_WRITECOPY) _tcscat(message, TEXT(" PAGE_EXECUTE_WRITECOPY"));
    if(mbi.Protect&PAGE_NOACCESS)          _tcscat(message, TEXT(" PAGE_NOACCESS"));
    if(mbi.Protect&PAGE_READONLY)          _tcscat(message, TEXT(" PAGE_READONLY"));
    if(mbi.Protect&PAGE_READWRITE)         _tcscat(message, TEXT(" PAGE_READWRITE"));
    if(mbi.Protect&PAGE_WRITECOPY)         _tcscat(message, TEXT(" PAGE_WRITECOPY"));
    if(mbi.Protect&PAGE_GUARD)             _tcscat(message, TEXT(" PAGE_GUARD"));
    if(mbi.Protect&PAGE_NOCACHE)           _tcscat(message, TEXT(" PAGE_NOCACHE"));
    if(mbi.Protect&PAGE_WRITECOMBINE)      _tcscat(message, TEXT(" PAGE_WRITECOMBINE"));
    if(mbi.Type&MEM_IMAGE)                 _tcscat(message, TEXT(" MEM_IMAGE"));
    if(mbi.Type&MEM_MAPPED)                _tcscat(message, TEXT(" MEM_MAPPED"));
    if(mbi.Type&MEM_PRIVATE)               _tcscat(message, TEXT(" MEM_PRIVATE"));
   } // END of if()
   _tcscat(message, TEXT("\n"));
   _tprintf(message);
   //
   baseadr=(LPBYTE)mbi.BaseAddress+mbi.RegionSize;
   if(baseadr==0x0) break;
 } else {
   #ifndef _WIN64 // for Win32
   _tcscpy(bar, TEXT("--------"));
   #else          // for Win64
   _tcscpy(bar, TEXT("----------------"));
   #endif
   _tprintf(TEXT("%p %s Cannot access\n"), baseadr, bar);
   break;
 } // END of if()

} // END of while()


}

32-bit版(/LARGEADDRESSAWAREなし)と64-bit版とを実行します。(仮想アドレス空間の使用状況はプログラムによっても変わってきますし、どのようなDLLがロードされるかによっても変わってきます。下記に示すのは、あくまでも一例です。)

D:\>memview

Address  Size(bytes)  Status
00000000 00010000 MEM_FREE
00010000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00011000 0000f000 MEM_FREE
00020000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00021000 0000f000 MEM_FREE
00030000 000fd000 MEM_RESERVE MEM_PRIVATE
0012D000 00001000 MEM_COMMIT PAGE_READWRITE PAGE_GUARD MEM_PRIVATE
0012E000 00002000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00130000 00003000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00133000 0000d000 MEM_FREE
00140000 00001000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00141000 0000f000 MEM_FREE
00150000 00004000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00154000 000fc000 MEM_RESERVE MEM_PRIVATE
00250000 00006000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00256000 0000a000 MEM_RESERVE MEM_PRIVATE
00260000 00003000 MEM_COMMIT PAGE_READWRITE MEM_MAPPED
00263000 0000d000 MEM_RESERVE MEM_MAPPED
00270000 00016000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00286000 0000a000 MEM_FREE
00290000 0003d000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
002CD000 00003000 MEM_FREE
002D0000 00041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00311000 0000f000 MEM_FREE
00320000 00006000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00326000 0000a000 MEM_FREE
00330000 00041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00371000 0000f000 MEM_FREE
00380000 00007000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00387000 00009000 MEM_RESERVE MEM_PRIVATE
00390000 00003000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00393000 0006d000 MEM_FREE
00400000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
00401000 00021000 MEM_COMMIT PAGE_EXECUTE_WRITECOPY MEM_IMAGE
00422000 00046000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
00468000 0000e000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
00476000 00006000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
0047C000 7c384000 MEM_FREE
7C800000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C801000 00082000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
7C883000 00003000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
7C886000 00002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
7C888000 000a9000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C931000 0000f000 MEM_FREE
7C940000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C941000 0007b000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
7C9BC000 00003000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
7C9BF000 00002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
7C9C1000 0001c000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C9DD000 02d13000 MEM_FREE
7F6F0000 00007000 MEM_COMMIT PAGE_EXECUTE_READ MEM_MAPPED
7F6F7000 000f9000 MEM_RESERVE MEM_MAPPED
7F7F0000 007c0000 MEM_FREE
7FFB0000 0002a000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
7FFDA000 00004000 MEM_FREE
7FFDE000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
7FFDF000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
7FFE0000 00001000 MEM_COMMIT PAGE_READONLY MEM_PRIVATE
7FFE1000 0000f000 MEM_RESERVE PAGE_NOACCESS MEM_PRIVATE
7FFF0000 -------- Cannot access

D:\>

D:\>memview
Address  Size(bytes)  Status
0000000000000000 0000000000010000 MEM_FREE
0000000000010000 0000000000001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
0000000000011000 000000000000f000 MEM_FREE
0000000000020000 0000000000001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
0000000000021000 000000000000f000 MEM_FREE
0000000000030000 00000000000fc000 MEM_RESERVE MEM_PRIVATE
000000000012C000 0000000000002000 MEM_COMMIT PAGE_READWRITE PAGE_GUARD MEM_PRIVATE
000000000012E000 0000000000002000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
0000000000130000 0000000000005000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
0000000000135000 000000000000b000 MEM_FREE
0000000000140000 0000000000006000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
0000000000146000 00000000000fa000 MEM_RESERVE MEM_PRIVATE
0000000000240000 0000000000004000 MEM_COMMIT PAGE_READWRITE MEM_MAPPED
0000000000244000 000000000000c000 MEM_RESERVE MEM_MAPPED
0000000000250000 0000000000016000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
0000000000266000 000000000000a000 MEM_FREE
0000000000270000 0000000000034000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00000000002A4000 000000000000c000 MEM_FREE
00000000002B0000 0000000000041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00000000002F1000 000000000000f000 MEM_FREE
0000000000300000 0000000000006000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
0000000000306000 000000000000a000 MEM_FREE
0000000000310000 0000000000041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
0000000000351000 000000000000f000 MEM_FREE
0000000000360000 0000000000010000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
0000000000370000 0000000000003000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
0000000000373000 000000000008d000 MEM_FREE
0000000000400000 0000000000001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
0000000000401000 000000000000a000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
000000000040B000 0000000000003000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
000000000040E000 0000000000004000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
0000000000412000 0000000000001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
0000000000413000 000000000000d000 MEM_FREE
0000000000420000 0000000000027000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
0000000000447000 00000000000d9000 MEM_RESERVE MEM_PRIVATE
0000000000520000 00000000777c0000 MEM_FREE
0000000077CE0000 0000000000001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
0000000077CE1000 00000000000e4000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
0000000077DC5000 0000000000004000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
0000000077DC9000 0000000000001000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
0000000077DCA000 00000000000c8000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
0000000077E92000 000000000000e000 MEM_FREE
0000000077EA0000 0000000000001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
0000000077EA1000 00000000000e3000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
0000000077F84000 0000000000006000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
0000000077F8A000 0000000000002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
0000000077F8C000 0000000000067000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
0000000077FF3000 0000000006fed000 MEM_FREE
000000007EFE0000 0000000000009000 MEM_COMMIT PAGE_EXECUTE_READ MEM_MAPPED
000000007EFE9000 00000000000f7000 MEM_RESERVE MEM_MAPPED
000000007F0E0000 0000000000f00000 MEM_RESERVE MEM_PRIVATE
000000007FFE0000 0000000000001000 MEM_COMMIT PAGE_READONLY MEM_PRIVATE
000000007FFE1000 000000000000f000 MEM_RESERVE MEM_PRIVATE
000000007FFF0000 000007ff7ffc0000 MEM_FREE
000007FFFFFB0000 000000000002a000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
000007FFFFFDA000 0000000000003000 MEM_FREE
000007FFFFFDD000 0000000000002000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
000007FFFFFDF000 0000000000001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
000007FFFFFE0000 0000000000010000 MEM_RESERVE PAGE_NOACCESS MEM_PRIVATE
000007FFFFFF0000 ---------------- Cannot access

D:\>

ハイライト表示になっている箇所にご注目ください。32-bit版では、アドレス0x47C000から0x7c384000byte(1987MB弱)の未使用エリアがあります。さらにアドレス0x7FFF0000(全4GBの仮想アドレス空間のうち上位2GBは0x80000000から始まるので、ちょうどその64KB前になる。)から上位にはアクセスできないこともわかります。64-bit版では、アドレス0x7FFF0000から0x7ff7ffc0000byte(8189GB弱)の未使用エリアがあります。(なぜこのエリアをフルに満たすだけのサイズで確保できなかったのかは不明。)アドレス0x520000から始まるエリアにも0x777c0000byte(1911MB弱)の未使用エリアがあります。アドレス0x7FFFFFF0000(全16TBの仮想アドレス空間のうち上位8TBは0x80000000000から始まるので、ちょうどその64KB前になる。)から上位にはアクセスできないこともわかります。

次に/LARGEADDRESSAWAREオプションを付けてビルドしたもの(32-bit版)を4GT RAM TuningなWindowsXP SP2(boot.iniに/3GBオプションを付加)とx64版WindowsXP(WOW64)上で実行します。

D:\>memview
Address  Size(bytes)  Status
00000000 00010000 MEM_FREE
00010000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00011000 0000f000 MEM_FREE
00020000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00021000 0000f000 MEM_FREE
00030000 000fd000 MEM_RESERVE MEM_PRIVATE
0012D000 00001000 MEM_COMMIT PAGE_READWRITE PAGE_GUARD MEM_PRIVATE
0012E000 00002000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00130000 00003000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00133000 0000d000 MEM_FREE
00140000 00001000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00141000 0000f000 MEM_FREE
00150000 00004000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00154000 000fc000 MEM_RESERVE MEM_PRIVATE
00250000 00006000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00256000 0000a000 MEM_RESERVE MEM_PRIVATE
00260000 00003000 MEM_COMMIT PAGE_READWRITE MEM_MAPPED
00263000 0000d000 MEM_RESERVE MEM_MAPPED
00270000 00016000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00286000 0000a000 MEM_FREE
00290000 0003d000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
002CD000 00003000 MEM_FREE
002D0000 00041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00311000 0000f000 MEM_FREE
00320000 00006000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00326000 0000a000 MEM_FREE
00330000 00041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00371000 0000f000 MEM_FREE
00380000 00007000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00387000 00009000 MEM_RESERVE MEM_PRIVATE
00390000 00003000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00393000 0006d000 MEM_FREE
00400000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
00401000 00021000 MEM_COMMIT PAGE_EXECUTE_WRITECOPY MEM_IMAGE
00422000 00046000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
00468000 0000e000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
00476000 00006000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
0047C000 7c384000 MEM_FREE
7C800000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C801000 00082000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
7C883000 00003000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
7C886000 00002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
7C888000 000a9000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C931000 0000f000 MEM_FREE
7C940000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C941000 0007b000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
7C9BC000 00003000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
7C9BF000 00002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
7C9C1000 0001c000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7C9DD000 02d13000 MEM_FREE
7F6F0000 00007000 MEM_COMMIT PAGE_EXECUTE_READ MEM_MAPPED
7F6F7000 000f9000 MEM_RESERVE MEM_MAPPED
7F7F0000 007f0000 MEM_FREE
7FFE0000 00001000 MEM_COMMIT PAGE_READONLY MEM_PRIVATE
7FFE1000 3ffcf000 MEM_FREE
BFFB0000 0002a000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
BFFDA000 00004000 MEM_FREE
BFFDE000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
BFFDF000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
BFFE0000 00010000 MEM_RESERVE PAGE_NOACCESS MEM_PRIVATE
BFFF0000 -------- Cannot access

D:\>

D:\>memview
Address  Size(bytes)  Status
00000000 00010000 MEM_FREE
00010000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00011000 0000f000 MEM_FREE
00020000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00021000 0000f000 MEM_FREE
00030000 000fb000 MEM_RESERVE MEM_PRIVATE
0012B000 00002000 MEM_COMMIT PAGE_READWRITE PAGE_GUARD MEM_PRIVATE
0012D000 00003000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00130000 00006000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00136000 0000a000 MEM_FREE
00140000 00005000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00145000 0007b000 MEM_RESERVE MEM_PRIVATE
001C0000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
001C1000 0000f000 MEM_FREE
001D0000 000fd000 MEM_RESERVE MEM_PRIVATE
002CD000 00001000 MEM_COMMIT PAGE_READWRITE PAGE_GUARD MEM_PRIVATE
002CE000 00002000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
002D0000 00004000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
002D4000 000fc000 MEM_RESERVE MEM_PRIVATE
003D0000 00004000 MEM_COMMIT PAGE_READWRITE MEM_MAPPED
003D4000 0000c000 MEM_RESERVE MEM_MAPPED
003E0000 00016000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
003F6000 0000a000 MEM_FREE
00400000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
00401000 00021000 MEM_COMMIT PAGE_EXECUTE_WRITECOPY MEM_IMAGE
00422000 00046000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
00468000 0000e000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
00476000 00006000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
0047C000 00004000 MEM_FREE
00480000 00034000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
004B4000 0000c000 MEM_FREE
004C0000 00041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00501000 0000f000 MEM_FREE
00510000 00006000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00516000 0000a000 MEM_FREE
00520000 00041000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00561000 0000f000 MEM_FREE
00570000 00007000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
00577000 00009000 MEM_RESERVE MEM_PRIVATE
00580000 00003000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
00583000 7758d000 MEM_FREE
77B10000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77B11000 00004000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
77B15000 00001000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
77B16000 00003000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77B19000 00007000 MEM_FREE
77B20000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77B21000 0003c000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
77B5D000 00001000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
77B5E000 00005000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
77B63000 00006000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77B69000 00007000 MEM_FREE
77B70000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77B71000 00031000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
77BA2000 00009000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
77BAB000 00001000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
77BAC000 00001000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
77BAD000 00001000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
77BAE000 00001000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
77BAF000 00001000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
77BB0000 00001000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
77BB1000 00005000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77BB6000 0000a000 MEM_FREE
77BC0000 0010f000 MEM_RESERVE MEM_PRIVATE
77CCF000 00011000 MEM_FREE
77CE0000 001b2000 MEM_RESERVE MEM_PRIVATE
77E92000 0000e000 MEM_FREE
77EA0000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77EA1000 000e3000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
77F84000 00006000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
77F8A000 00002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
77F8C000 00067000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
77FF3000 054dd000 MEM_FREE
7D4D0000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7D4D1000 0000f000 MEM_RESERVE MEM_IMAGE
7D4E0000 00083000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
7D563000 0000d000 MEM_RESERVE MEM_IMAGE
7D570000 00003000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
7D573000 00002000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
7D575000 0000b000 MEM_RESERVE MEM_IMAGE
7D580000 00047000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7D5C7000 00009000 MEM_RESERVE MEM_IMAGE
7D5D0000 00010000 MEM_FREE
7D5E0000 00001000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7D5E1000 0000f000 MEM_RESERVE MEM_IMAGE
7D5F0000 00085000 MEM_COMMIT PAGE_EXECUTE_READ MEM_IMAGE
7D675000 0000b000 MEM_RESERVE MEM_IMAGE
7D680000 00004000 MEM_COMMIT PAGE_READWRITE MEM_IMAGE
7D684000 00001000 MEM_COMMIT PAGE_WRITECOPY MEM_IMAGE
7D685000 0000b000 MEM_RESERVE MEM_IMAGE
7D690000 00049000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7D6D9000 00007000 MEM_RESERVE MEM_IMAGE
7D6E0000 00004000 MEM_COMMIT PAGE_READONLY MEM_IMAGE
7D6E4000 0000c000 MEM_RESERVE MEM_IMAGE
7D6F0000 018f0000 MEM_FREE
7EFE0000 00009000 MEM_COMMIT PAGE_EXECUTE_READ MEM_MAPPED
7EFE9000 000f7000 MEM_RESERVE MEM_MAPPED
7F0E0000 00f00000 MEM_RESERVE MEM_PRIVATE
7FFE0000 00001000 MEM_COMMIT PAGE_READONLY MEM_PRIVATE
7FFE1000 0000f000 MEM_RESERVE MEM_PRIVATE
7FFF0000 7ffc0000 MEM_FREE
FFFB0000 0002a000 MEM_COMMIT PAGE_READONLY MEM_MAPPED
FFFDA000 00001000 MEM_FREE
FFFDB000 00003000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
FFFDE000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
FFFDF000 00001000 MEM_COMMIT PAGE_READWRITE MEM_PRIVATE
FFFE0000 00010000 MEM_RESERVE PAGE_NOACCESS MEM_PRIVATE
FFFF0000 -------- Cannot access

D:\>

/3GBの方では、アドレス0x47C000から0x7c384000byte(1987MB弱)の未使用エリアがあります。アドレス0x7FFE1000から始まるエリアにも0x3ffcf000byte(1023MB弱)の未使用エリアがあります。アクセスできないエリアがアドレス0xBFFF0000(全4GBの仮想アドレス空間のうち上位1GBは0xC0000000から始まるので、ちょうどその64KB前になる。)からになっています。通常よりも1GB広くなっていることがわかります。

WOW64の方では、アドレス0x7FFF0000から0x7ffc0000byte(2047MB弱)の未使用エリアがあります。アドレス0x583000から始まるエリアにも0x7758d000byte(1909MB弱)の未使用エリアがあります。アクセスできないエリアがアドレス0xFFFF0000から始まる最上位64KBだけ、要するに全4GBの仮想アドレス空間をほとんどまるごと使えることがわかります。

起草日:2005年1月8日(土)(www.marbacka.net内の別のサイトで公開)
最終更新日:2017年2月19日(日)

スポンサーリンク