VirtualAlloc2 関数 (memoryapi.h)
指定されたプロセスの仮想アドレス空間内のメモリ領域の状態を予約、コミット、または変更します (割り当てられたメモリは 0 に初期化されます)。
構文
PVOID VirtualAlloc2(
[in, optional] HANDLE Process,
[in, optional] PVOID BaseAddress,
[in] SIZE_T Size,
[in] ULONG AllocationType,
[in] ULONG PageProtection,
[in, out, optional] MEM_EXTENDED_PARAMETER *ExtendedParameters,
[in] ULONG ParameterCount
);
パラメーター
[in, optional] Process
プロセスへのハンドル。 この関数は、このプロセスの仮想アドレス空間内にメモリを割り当てます。
ハンドルには、PROCESS_VM_OPERATION アクセス権が必要です。 詳細については、「プロセス セキュリティとアクセス権の
[in, optional] BaseAddress
割り当てるページの領域に必要な開始アドレスを指定するポインター。
BaseAddress
baseAddress
このアドレスが InitializeEnclave
初期化したエンクレーブ内のアドレスが失敗した場合、割り当て操作は ERROR_INVALID_ADDRESS エラーで失敗します。 これは、動的メモリ管理 (つまり SGX1) をサポートしていないエンクレーブに当てはまります。 SGX2 エンクレーブは割り当てを許可し、ページは割り当てられた後にエンクレーブによって受け入れられる必要があります。
[in] Size
割り当てるメモリ領域のサイズ (バイト単位)。
サイズは常にページ サイズの倍数である必要があります。
BaseAddress
[in] AllocationType
メモリ割り当ての種類。 このパラメーターには、次のいずれかの値が含まれている必要があります。
このパラメーターでは、次の値を指定することもできます。
価値 | 意味 |
---|---|
|
大きなページ サポート サイズと配置は、大きなページの最小値の倍数である必要があります。 この値を取得するには、GetLargePageMinimum 関数を使用します。 この値を指定する場合は、MEM_RESERVE と MEM_COMMITも指定する必要があります。 |
|
可能であれば、64K ページを使用してメモリをマップするためのヒント。
64K ページは、サイズが 64K で、仮想的および物理的に連続し、仮想的および物理的に 64K の境界に配置されたメモリ領域です。 既定では、MEM_64K_PAGESを使用して割り当てられたメモリはページング可能であり、メモリをバックアップする物理ページは必要に応じて (アクセス時に) 割り当てられます。 物理メモリが断片化されすぎて物理的に連続した 64K ページをアセンブルできない場合は、MEM_64K_PAGES割り当てのすべてまたは一部が、代わりに連続していない小さなページを使用してマップされる可能性があります。 MEM_64K_PAGESが MEM_EXTENDED_PARAMETER_NONPAGED 属性と組み合わされている場合、割り当ては、非ページ 64K ページを使用してマップされます。 その場合、連続する 64K ページを取得できない場合、割り当ては失敗します。 MEM_64K_PAGESを指定する場合、Size パラメーターと BaseAddress パラメーターの両方が 64K の倍数である必要があります (BaseAddress は NULL である可能性があります)。 |
|
アドレスウィンドウ拡張 (AWE) ページ この値は、MEM_RESERVE で使用する必要があり、他の値は使用できません。 |
|
可能な限り高いアドレスでメモリを割り当てます。 これは、特に割り当てが多い場合に、通常の割り当てよりも遅くなる可能性があります。 |
[in] PageProtection
割り当てるページの領域のメモリ保護。 ページをコミットする場合は、
BaseAddress
- PAGE_NOACCESS
- PAGE_GUARD
- PAGE_NOCACHE
- PAGE_WRITECOMBINE
エンクレーブに動的メモリを割り当てるときは、PageProtection パラメーターを PAGE_READWRITE または PAGE_EXECUTE_READWRITEする必要があります。
[in, out, optional] ExtendedParameters
MEM_EXTENDED_PARAMETER型の 1 つ以上の拡張パラメーターへの省略可能なポインター。 これらの各拡張パラメーター値には、MemExtendedParameterAddressRequirements または MemExtendedParameterNumaNodeの Type フィールドを持つことができます。 拡張パラメーター
[in] ParameterCount
ExtendedParametersによって指される拡張パラメーターの数。
戻り値
関数が成功した場合、戻り値はページの割り当てられた領域のベース アドレスです。
関数が失敗した場合、戻り値は NULL
備考
この関数を使用すると、次を指定できます。
- 仮想アドレス空間の範囲と、新しい割り当てに対する 2 乗アライメント制限
- 任意の数の拡張パラメーター
- 拡張パラメーターとしての物理メモリの優先 NUMA ノード (ExtendedParameters パラメーターを参照)
- プレースホルダー操作 (具体的には置換)。
この API は、高パフォーマンスのゲームやサーバー アプリケーションをサポートするために仮想メモリを管理するための特殊な手法を提供します。 たとえば、プレースホルダーを使用すると、予約済みのメモリ範囲を明示的にパーティション分割し、オーバーレイし、再マップできます。これは、任意に拡張可能な領域または仮想メモリ リング バッファーを実装するために使用できます。 VirtualAlloc2 では、特定のメモリアラインメントを使用してメモリを割り当てることもできます。
各ページには、ページの状態
- 予約ページのリージョンをコミットする
- 無料ページのリージョンを予約する
- 空きページの領域を同時に予約してコミットする
VirtualAlloc2 は、既にコミットされているが、既に予約されているページを予約できないページをコミットできます。 つまり、既にコミットされているかどうかに関係なく、ページの範囲をコミットでき、関数は失敗しません。 ただし、一般に、既にコミットされている多数のページをコミットすると、VirtualAlloc2 呼び出しにかかる時間が大幅に長くなる可能性があるため、ほとんどのコミットされていないページの最小範囲のみを指定する必要があります。
VirtualAlloc2 を使用すると、ページブロックを予約し、その後、VirtualAlloc2 に対して追加の呼び出しを行って、予約ブロックから個々のページをコミットできます。 これにより、プロセスは、必要になるまで物理ストレージを消費することなく、その仮想アドレス空間の範囲を予約できます。
動的に生成されたコードを実行するには、VirtualAlloc2 を使用してメモリを割り当て、VirtualProtectEx 関数を使用して PAGE_EXECUTE アクセスを許可します。
VirtualAlloc2 関数を使用すると、指定されたプロセスの仮想アドレス空間内のメモリの アドレス ウィンドウ拡張 (AWE) 領域を予約できます。 その後、このメモリ領域を使用して、アプリケーションの必要に応じて、仮想メモリとの間で物理ページをマップできます。 MEM_PHYSICAL と MEM_RESERVE の値は、AllocationType パラメーターで設定する必要があります。 MEM_COMMIT 値は設定しないでください。 ページ保護を PAGE_READWRITEに設定する必要があります。
VirtualFreeEx 関数は、コミットされたページのコミットを解除したり、ページのストレージを解放したり、コミットされたページを同時にデコミットして解放したりできます。 また、予約ページを解放して、無料のページにすることもできます。
実行可能なリージョンを作成する場合、呼び出し元のプログラムは、コードが設定されたら、FlushInstructionCache への適切な呼び出しによってキャッシュの一貫性を確保する責任を負います。 そうしないと、新しく実行可能なリージョンからコードを実行しようとすると、予期しない結果が発生する可能性があります。
例
シナリオ 1. 同じ共有メモリ セクションの 2 つの隣接するビューをマッピングして、循環バッファーを作成します。
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
//
// This function creates a ring buffer by allocating a pagefile-backed section
// and mapping two views of that section next to each other. This way if the
// last record in the buffer wraps it can still be accessed in a linear fashion
// using its base VA.
//
void*
CreateRingBuffer (
unsigned int bufferSize,
_Outptr_ void** secondaryView
)
{
BOOL result;
HANDLE section = nullptr;
SYSTEM_INFO sysInfo;
void* ringBuffer = nullptr;
void* placeholder1 = nullptr;
void* placeholder2 = nullptr;
void* view1 = nullptr;
void* view2 = nullptr;
GetSystemInfo (&sysInfo);
if ((bufferSize % sysInfo.dwAllocationGranularity) != 0) {
return nullptr;
}
//
// Reserve a placeholder region where the buffer will be mapped.
//
placeholder1 = (PCHAR) VirtualAlloc2 (
nullptr,
nullptr,
2 * bufferSize,
MEM_RESERVE | MEM_RESERVE_PLACEHOLDER,
PAGE_NOACCESS,
nullptr, 0
);
if (placeholder1 == nullptr) {
printf ("VirtualAlloc2 failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Split the placeholder region into two regions of equal size.
//
result = VirtualFree (
placeholder1,
bufferSize,
MEM_RELEASE | MEM_PRESERVE_PLACEHOLDER
);
if (result == FALSE) {
printf ("VirtualFreeEx failed, error %#x\n", GetLastError());
goto Exit;
}
placeholder2 = (void*) ((ULONG_PTR) placeholder1 + bufferSize);
//
// Create a pagefile-backed section for the buffer.
//
section = CreateFileMapping (
INVALID_HANDLE_VALUE,
nullptr,
PAGE_READWRITE,
0,
bufferSize, nullptr
);
if (section == nullptr) {
printf ("CreateFileMapping failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Map the section into the first placeholder region.
//
view1 = MapViewOfFile3 (
section,
nullptr,
placeholder1,
0,
bufferSize,
MEM_REPLACE_PLACEHOLDER,
PAGE_READWRITE,
nullptr, 0
);
if (view1 == nullptr) {
printf ("MapViewOfFile3 failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Ownership transferred, don't free this now.
//
placeholder1 = nullptr;
//
// Map the section into the second placeholder region.
//
view2 = MapViewOfFile3 (
section,
nullptr,
placeholder2,
0,
bufferSize,
MEM_REPLACE_PLACEHOLDER,
PAGE_READWRITE,
nullptr, 0
);
if (view2 == nullptr) {
printf ("MapViewOfFile3 failed, error %#x\n", GetLastError());
goto Exit;
}
//
// Success, return both mapped views to the caller.
//
ringBuffer = view1;
*secondaryView = view2;
placeholder2 = nullptr;
view1 = nullptr;
view2 = nullptr;
Exit:
if (section != nullptr) {
CloseHandle (section);
}
if (placeholder1 != nullptr) {
VirtualFree (placeholder1, 0, MEM_RELEASE);
}
if (placeholder2 != nullptr) {
VirtualFree (placeholder2, 0, MEM_RELEASE);
}
if (view1 != nullptr) {
UnmapViewOfFileEx (view1, 0);
}
if (view2 != nullptr) {
UnmapViewOfFileEx (view2, 0);
}
return ringBuffer;
}
int __cdecl wmain()
{
char* ringBuffer;
void* secondaryView;
unsigned int bufferSize = 0x10000;
ringBuffer = (char*) CreateRingBuffer (bufferSize, &secondaryView);
if (ringBuffer == nullptr) {
printf ("CreateRingBuffer failed\n");
return 0;
}
//
// Make sure the buffer wraps properly.
//
ringBuffer[0] = 'a';
if (ringBuffer[bufferSize] == 'a') {
printf ("The buffer wraps as expected\n");
}
UnmapViewOfFile (ringBuffer);
UnmapViewOfFile (secondaryView);
}
シナリオ 2. メモリを割り当てるときに優先 NUMA ノードを指定します。
void*
AllocateWithPreferredNode (size_t size, unsigned int numaNode)
{
MEM_EXTENDED_PARAMETER param = {0};
param.Type = MemExtendedParameterNumaNode;
param.ULong = numaNode;
return VirtualAlloc2 (
nullptr, nullptr,
size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE,
¶m, 1);
}
シナリオ 3. 特定の仮想アドレス範囲 (この例では 4 GB 未満) にメモリを割り当て、特定のアラインメントを使用します。
void*
AllocateAlignedBelow2GB (size_t size, size_t alignment)
{
MEM_ADDRESS_REQUIREMENTS addressReqs = {0};
MEM_EXTENDED_PARAMETER param = {0};
addressReqs.Alignment = alignment;
addressReqs.HighestEndingAddress = (PVOID)(ULONG_PTR) 0x7fffffff;
param.Type = MemExtendedParameterAddressRequirements;
param.Pointer = &addressReqs;
return VirtualAlloc2 (
nullptr, nullptr,
size,
MEM_RESERVE | MEM_COMMIT,
PAGE_READWRITE,
¶m, 1);
}
必要条件
要件 | 価値 |
---|---|
サポートされる最小クライアント | Windows 10 [デスクトップ アプリのみ] |
サポートされる最小サーバー | Windows Server 2016 [デスクトップ アプリのみ] |
ターゲット プラットフォーム の |
ウィンドウズ |
ヘッダー | memoryapi.h (Windows.h を含む) |
ライブラリ | onecore.lib |
DLL | Kernel32.dll |
関連項目
ReadProcessMemory の
仮想メモリ関数 の
VirtualFreeEx を
VirtualQuery の
WriteProcessMemory の