VirtualAlloc 関数 (memoryapi.h)
呼び出し元プロセスの仮想アドレス空間内のページ領域の状態を予約、コミット、または変更します。 この関数によって割り当てられたメモリは、自動的に 0 に初期化されます。
別のプロセスのアドレス空間にメモリを割り当てるには、 VirtualAllocEx 関数を使用します。
構文
LPVOID VirtualAlloc(
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
パラメーター
[in, optional] lpAddress
割り当てるリージョンの開始アドレス。 メモリが予約されている場合、指定されたアドレスは、割り当て粒度の最も近い倍数に切り捨てられます。 メモリが既に予約されており、コミットされている場合、アドレスは次のページ境界に切り捨てられます。 ホスト コンピューター上のページのサイズと割り当ての粒度を確認するには、 GetSystemInfo 関数を使用します。 このパラメーターが NULL の場合、システムはリージョンを割り当てる場所を決定します。
このアドレスが InitializeEnclave を呼び出して初期化していないエンクレーブ内にある場合、 VirtualAlloc はそのアドレスのエンクレーブに 0 のページを割り当てます。 ページは以前にコミットされていない必要があり、Intel Software Guard Extensions プログラミング モデルの EEXTEND 命令では測定されません。
アドレスが初期化したエンクレーブ内にある場合、割り当て操作は ERROR_INVALID_ADDRESS エラーで失敗します。 これは、動的メモリ管理 (つまり SGX1) をサポートしていないエンクレーブに当てはまります。 SGX2 エンクレーブは割り当てを許可し、ページは割り当てられた後にエンクレーブによって受け入れられる必要があります。
[in] dwSize
リージョンのサイズ (バイト単位)。 lpAddress パラメーターが NULL の場合、この値は次のページ境界に切り上げられます。 それ以外の場合、割り当てられたページには、 lpAddress から lpAddress+dwSize までの範囲内の 1 つ以上のバイトを含むすべてのページが含まれます。 つまり、ページ境界にまたがる 2 バイト範囲では、両方のページが割り当てられた領域に含まれます。
[in] flAllocationType
メモリ割り当ての種類。 このパラメーターには、次のいずれかの値が含まれている必要があります。
値 | 意味 |
---|---|
|
指定した予約済みメモリ ページに対して (メモリの全体的なサイズとディスク上のページング ファイルから) メモリ料金を割り当てます。 関数は、呼び出し元が後で最初にメモリにアクセスするときに、内容がゼロになることも保証します。 仮想アドレスが実際にアクセスされるまで、実際の物理ページは割り当てされません。
ページを 1 つのステップで予約してコミットするには、 を使用して MEM_RESERVEを指定せずにMEM_COMMITを指定して特定のアドレス範囲をコミットしようとすると、範囲全体が既に予約されていない限り、NULL 以外の lpAddress が失敗します。 結果のエラー コードは ERROR_INVALID_ADDRESS。 既にコミットされているページをコミットしようとしても、関数は失敗しません。 つまり、各ページの現在のコミットメント状態を最初に判断しなくても、ページをコミットできます。 lpAddress がエンクレーブ内のアドレスを指定する場合は、flAllocationType をMEM_COMMITする必要があります。 |
|
メモリまたはディスク上のページング ファイルに実際の物理ストレージを割り当てずに、プロセスの仮想アドレス空間の範囲を予約します。
予約ページは、 後続の VirtualAlloc 関数の呼び出しでコミットできます。 ページを 1 つのステップで予約してコミットするには、MEM_COMMIT MEM_RESERVE | を使用して VirtualAlloc を呼び出します。 malloc や LocalAlloc などの他のメモリ割り当て関数では、解放されるまで予約されたメモリ範囲を使用できません。 |
|
lpAddress および dwSize で指定されたメモリ範囲内のデータが関心を持たなくなったことを示します。 ページをページング ファイルから読み取ったり、ページング ファイルに書き込んだりしないでください。 ただし、メモリ ブロックは後でもう一度使用されるため、コミットを解除しないでください。 この値を他の値と共に使用することはできません。
この値を使用しても、 MEM_RESET で操作される範囲にゼロが含まれるという保証はありません。 範囲にゼロを含める場合は、メモリのコミットを解除してから、再コミットします。 MEM_RESETを指定すると、VirtualAlloc 関数は flProtect の値を無視します。 ただし、 flProtect を有効な保護値 ( PAGE_NOACCESS など) に設定する必要があります。 MEM_RESETを使用し、メモリの範囲がファイルにマップされている場合、VirtualAlloc はエラーを返します。 共有ビューは、ページング ファイルにマップされている場合にのみ使用できます。 |
|
MEM_RESET_UNDO は、MEM_RESETが以前に正常に 適用されたアドレス 範囲でのみ呼び出す必要があります。 これは、lpAddress および dwSize で指定された指定されたメモリ範囲内のデータが呼び出し元にとって重要であり、MEM_RESETの影響を取り消そうとしていることを示します。 関数が成功した場合、指定されたアドレス範囲のすべてのデータはそのままであることを意味します。 関数が失敗した場合、アドレス範囲のデータの少なくとも一部がゼロに置き換えられました。
この値を他の値と共に使用することはできません。 以前 にMEM_RESET されなかったアドレス範囲で MEM_RESET_UNDO が呼び出された場合、動作は未定義です。 MEM_RESETを指定すると、VirtualAlloc 関数は flProtect の値を無視します。 ただし、 flProtect を有効な保護値 ( PAGE_NOACCESS など) に設定する必要があります。 Windows Server 2008 R2、Windows 7、Windows Server 2008、Windows Vista、Windows Server 2003、Windows XP: MEM_RESET_UNDO フラグは、Windows 8してWindows Server 2012するまでサポートされません。 |
このパラメーターは、示されているように次の値を指定することもできます。
値 | 意味 |
---|---|
|
大きなページのサポートを使用してメモリを割り当てます。
サイズと配置は、大きいページの最小値の倍数である必要があります。 この値を取得するには、 GetLargePageMinimum 関数を 使用します。 この値を指定する場合は、 MEM_RESERVE と MEM_COMMITも指定する必要があります。 |
|
アドレス ウィンドウ拡張機能 (AWE) ページのマップに使用できるアドレス範囲を予約します。
この値は 、MEM_RESERVE で使用する必要があり、その他の値は使用できません。 |
|
可能な限り高いアドレスにメモリを割り当てます。 これは、特に割り当てが多い場合に、通常の割り当てよりも遅くなる可能性があります。 |
|
割り当てられたリージョン内の に書き込まれたページをシステムが追跡します。 この値を指定する場合は、 MEM_RESERVEも指定する必要があります。
リージョンが割り当てられたか、書き込み追跡状態がリセットされた後に書き込まれたページのアドレスを取得するには、 GetWriteWatch 関数を呼び出します。 書き込み追跡状態をリセットするには、GetWriteWatch または ResetWriteWatch を呼び出します。 書き込み追跡機能は、リージョンが解放されるまでメモリ領域に対して有効なままです。 |
[in] flProtect
割り当てられるページの領域のメモリ保護。 ページがコミットされている場合は、 メモリ保護定数のいずれかを指定できます。
lpAddress がエンクレーブ内のアドレスを指定する場合、flProtect は次の値のいずれにもできません。
- PAGE_NOACCESS
- PAGE_GUARD
- PAGE_NOCACHE
- PAGE_WRITECOMBINE
エンクレーブに動的メモリを割り当てる場合は、 flProtect パラメーターを PAGE_READWRITE または PAGE_EXECUTE_READWRITEする必要があります。
戻り値
関数が成功した場合、戻り値はページの割り当てられた領域のベース アドレスです。
関数が失敗した場合は、返される値は NULL です。 詳細なエラー情報を得るには、GetLastError を呼び出します。
解説
各ページには、関連付けられた ページの状態があります。 VirtualAlloc 関数は、次の操作を実行できます。
- 予約ページのリージョンをコミットする
- 無料ページのリージョンを予約する
- 無料ページの領域を同時に予約してコミットする
VirtualAlloc は予約ページを予約できません。 既にコミットされているページをコミットできます。 つまり、既にコミットされているかどうかに関係なく、ページの範囲をコミットでき、関数は失敗しません。
VirtualAlloc を使ってページのブロックを予約し、VirtualAlloc を追加で呼び出して予約したブロックから個々のページをコミットすることができます。 こうすることで、プロセスで必要になるまで物理ストレージを使わずに、仮想アドレス空間の範囲を予約することができます。
lpAddress パラメーターが NULL でない場合、関数は lpAddress パラメーターと dwSize パラメーターを使用して、割り当てられるページの領域を計算します。 ページの範囲全体の現在の状態は、 flAllocationType パラメーターで指定された割り当ての型と互換性がある必要があります。 それ以外の場合、関数は失敗し、どのページも割り当てされません。 この互換性要件では、前に説明したように、既にコミットされたページのコミットは除外されません。
動的に生成されたコードを実行するには、 VirtualAlloc を使用してメモリを割り当て、 VirtualProtect 関数を使用して PAGE_EXECUTEアクセスを 許可します。
VirtualAlloc 関数を使用すると、指定したプロセスの仮想アドレス空間内のメモリのアドレス ウィンドウ拡張機能 (AWE) 領域を予約できます。 その後、このメモリ領域を使用して、アプリケーションで必要に応じて仮想メモリとの間で物理ページをマップできます。 MEM_PHYSICALとMEM_RESERVEの値は、AllocationType パラメーターで設定する必要があります。 MEM_COMMIT値を設定することはできません。 ページ保護は 、PAGE_READWRITEに設定する必要があります。
VirtualFree 関数は、コミットされたページのコミット解除、ページのストレージの解放、またはコミットされたページのコミット解除と解放を同時に行うことができます。 また、予約ページを解放して、無料のページにすることもできます。
実行可能なリージョンを作成する場合、呼び出し元プログラムは、コードが設定された後に FlushInstructionCache を適切に呼び出すことでキャッシュの一貫性を確保する責任を負います。 そうしないと、新しく実行可能なリージョンからコードを実行しようとすると、予期しない結果が生成される可能性があります。
例
例については、「メモリの 予約とコミット」を参照してください。
要件
サポートされている最小のクライアント | Windows XP [デスクトップ アプリ | UWP アプリ] |
サポートされている最小のサーバー | Windows Server 2003 [デスクトップ アプリのみ | UWP アプリ] |
対象プラットフォーム | Windows |
ヘッダー | memoryapi.h (Windows.h、Memoryapi.h を含む) |
Library | onecore.lib |
[DLL] | Kernel32.dll |
関連項目
フィードバック
https://aka.ms/ContentUserFeedback」を参照してください。
以下は間もなく提供いたします。2024 年を通じて、コンテンツのフィードバック メカニズムとして GitHub の issue を段階的に廃止し、新しいフィードバック システムに置き換えます。 詳細については、「フィードバックの送信と表示