VirtualAlloc2FromApp 函数 (memoryapi.h)

保留、提交或更改调用进程的虚拟地址空间中页面区域的状态。 此函数分配的内存会自动初始化为零。

使用此函数,可以:对于新分配,请指定一系列虚拟地址空间和 2 元对齐限制;指定任意数量的扩展参数;将物理内存的首选 NUMA 节点指定为扩展参数;并指定占位符操作(具体而言,替换)。

若要指定 NUMA 节点,请参阅 ExtendedParameters 参数。

语法

PVOID VirtualAlloc2FromApp(
  [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

为要分配的页面区域指定所需起始地址的指针。

如果 BaseAddressNULL,则该函数将确定分配区域的位置。

如果 BaseAddressNULL,则提供的任何 MEM_ADDRESS_REQUIREMENTS 结构都必须包含所有零,并且基址必须是系统分配粒度的倍数。 若要确定分配粒度,请使用 GetSystemInfo 函数。

[in] Size

要分配的内存区域的大小(以字节为单位)。

大小必须始终为页面大小的倍数。

如果 BaseAddressNULL,则该函数会将包含一个或多个字节的所有页面分配在从 BaseAddressBaseAddress+size。 例如,这意味着跨页边界的 2 字节范围会导致函数分配这两个页面。

[in] AllocationType

内存分配的类型。 此参数必须包含以下值之一。

价值 意义
MEM_COMMIT
0x00001000
为指定的保留内存页分配内存费用(从内存的总体大小和磁盘上的分页文件)。 该函数还保证当调用方稍后最初访问内存时,内容将为零。 除非实际访问虚拟地址/直到实际访问虚拟地址,否则不会分配实际物理页。

若要在一个步骤中保留和提交页面,请使用 MEM_COMMIT | MEM_RESERVE调用 virtual2AllocFromApp

除非已保留整个范围,否则尝试通过指定不带 MEM_RESERVEMEM_COMMITNULLBaseAddress 来尝试提交特定地址范围。 生成的错误代码 ERROR_INVALID_ADDRESS

尝试提交已提交的页面不会导致函数失败。 这意味着可以提交页面,而无需首先确定每个页面的当前承诺状态。

MEM_RESERVE
0x00002000
保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。

可以在后续调用 Virtual2AllocFromApp 函数时提交保留页。 若要在一个步骤中保留和提交页面,请使用 MEM_COMMIT | MEM_RESERVE调用 Virtual2AllocFromApp

其他内存分配函数(如 mallocLocalAlloc)在释放之前无法使用保留的内存范围。

MEM_REPLACE_PLACEHOLDER
0x00004000
将占位符替换为正常的专用分配。 仅支持数据/pf 支持的分区视图(无图像、物理内存等)。 替换占位符时,BaseAddressSize 必须与占位符的占位符完全匹配,并且提供的任何 MEM_ADDRESS_REQUIREMENTS 结构都必须包含所有零。

将占位符替换为专用分配后,若要将该分配释放回占位符,请参阅 VirtualFreedwFreeType 参数,并 VirtualFreeEx

占位符是保留内存区域的类型。

MEM_RESERVE_PLACEHOLDER
0x00040000
若要创建占位符,请调用 VirtualAlloc2,并将 MEM_RESERVE | MEM_RESERVE_PLACEHOLDERPageProtection 设置为 PAGE_NOACCESS。 若要释放/拆分/合并占位符,请参阅 VirtualFreedwFreeType 参数,VirtualFreeEx

占位符是保留内存区域的类型。

MEM_RESET
0x00080000
指示 BaseAddress大小 指定的内存范围中的数据不再感兴趣。 不应从分页文件读取或写入页面。 但是,内存块稍后将再次使用,因此不应将其取消提交。 此值不能用于任何其他值。

使用此值不能保证使用 MEM_RESET 操作的范围将包含零。 如果希望该区域包含零,请取消提交内存,然后重新提交内存。

指定 MEM_RESET时,Virtual2AllocFromApp 函数将忽略 保护的值。 但是,仍必须将保护 设置为有效的保护值,例如 PAGE_NOACCESS

Virtual2AllocFromApp 如果使用 MEM_RESET 并且内存范围映射到文件,则返回错误。 仅当共享视图映射到分页文件时,才可接受。

MEM_RESET_UNDO
0x1000000
MEM_RESET_UNDO 只应在之前成功应用 MEM_RESET 的地址范围上调用。 它表示,BaseAddress 指定的指定内存范围中的数据和 大小 对调用方感兴趣,并尝试扭转 MEM_RESET的影响。 如果函数成功,则表示指定地址范围中的所有数据都保持不变。 如果函数失败,则地址范围中的至少一些数据已替换为零。

此值不能用于任何其他值。 如果在之前未 MEM_RESET 的地址范围上调用 MEM_RESET_UNDO,则行为是未定义的。 指定 MEM_RESET时,Virtual2AllocFromApp 函数将忽略 保护的值。 但是,仍必须将保护 设置为有效的保护值,例如 PAGE_NOACCESS

 

此参数还可以按指示指定以下值。

价值 意义
MEM_LARGE_PAGES
0x20000000
使用 大型页面支持分配内存。

大小和对齐方式必须是大页最小值的倍数。 若要获取此值,请使用 GetLargePageMinimum 函数。

如果指定此值,还必须指定 MEM_RESERVEMEM_COMMIT

MEM_PHYSICAL
0x00400000
保留可用于映射 地址窗口扩展插件(AWE)页的地址范围。

此值必须与 MEM_RESERVE 一起使用,并且不能用于其他值。

MEM_TOP_DOWN
0x00100000
以最高可能地址分配内存。 这比常规分配要慢,尤其是在分配很多时。
MEM_WRITE_WATCH
0x00200000
使系统跟踪写入到分配区域中的页面。 如果指定此值,还必须指定 MEM_RESERVE

若要检索自分配区域或重置写入跟踪状态以来已写入的页面的地址,请调用 GetWriteWatch 函数。 若要重置写入跟踪状态,请调用 GetWriteWatchResetWriteWatch。 写入跟踪功能将一直为内存区域启用,直到释放该区域。

[in] PageProtection

要分配的页面区域的内存保护。 如果要提交页面,则可以指定内存保护常量之一。 以下常量生成错误:

  • PAGE_EXECUTE
  • PAGE_EXECUTE_READ
  • PAGE_EXECUTE_READWRITE
  • PAGE_EXECUTE_WRITECOPY

[in, out, optional] ExtendedParameters

指向 MEM_EXTENDED_PARAMETER类型的一个或多个扩展参数的可选指针。 每个扩展参数值本身都可以具有 Type 字段,MemExtendedParameterAddressRequirementsMemExtendedParameterNumaNode。 如果未提供 MemExtendedParameterNumaNode 扩展参数,则行为与 VirtualAlloc/MapViewOfFile 函数(即,物理页的首选 NUMA 节点)是根据首次访问内存的线程的理想处理器确定的。

[in] ParameterCount

ExtendedParameters指向的扩展参数数。

返回值

如果函数成功,则返回值是页面分配区域的基址。

如果函数失败,则返回值 NULL。 若要获取扩展的错误信息,请调用 GetLastError

言论

此 API 有助于支持高性能游戏和服务器应用程序,这些应用程序在管理虚拟地址空间方面有特定要求。 例如,将内存映射在以前保留的区域之上;这可用于实现自动包装环缓冲区。 分配具有特定对齐方式的内存;例如,若要使应用程序能够按需提交大型/巨大的页面映射区域。

可以从具有实时 (JIT) 功能的 Windows 应用商店应用中调用 Virtual2AllocFromApp,以使用 JIT 功能。 应用必须在应用清单文件中包括 codeGeneration 功能才能使用 JIT 功能。

每个页面都有一个关联的 页面状态Virtual2AllocFromApp 函数可以执行以下操作:

  • 提交保留页的区域
  • 保留免费页面的区域
  • 同时保留并提交一个免费页面区域
Virtual2AllocFromApp 无法保留保留页。 它可以提交已提交的页面。 这意味着你可以提交一系列页面,无论它们是否已提交,并且函数不会失败。

可以使用 Virtual2AllocFromApp 来保留页面块,然后对 virtual2AllocFromApp 进行其他调用,以提交保留块中的单个页面。 这样一个进程就可以保留其虚拟地址空间的范围,而无需消耗物理存储,直到需要它。

如果 BaseAddress 参数未 NULL,则该函数使用 BaseAddress大小 参数来计算要分配的页面区域。 整个页面范围的当前状态必须与 AllocationType 参数指定的分配类型兼容。 否则,该函数将失败,并且未分配任何页面。 如前所述,此兼容性要求不排除提交已提交的页面。

Virtual2AllocFromApp 不允许创建可执行页面。

Virtual2AllocFromApp 函数可用于在指定进程的虚拟地址空间中保留内存的 地址窗口扩展(AWE)区域。 然后,可以使用此内存区域根据应用程序的要求将物理页映射到虚拟内存中和传出虚拟内存。 必须在 AllocationType 参数中设置 MEM_PHYSICALMEM_RESERVE 值。 不能设置 MEM_COMMIT 值。 页面保护必须设置为 PAGE_READWRITE

VirtualFree 函数可以取消提交页面、释放页面的存储,也可以同时取消提交和释放已提交的页面。 它还可以释放保留页,使其成为免费页面。

创建可执行的区域时,调用程序负责确保在代码设置到位后通过适当的调用 FlushInstructionCache 缓存一致性。 否则,尝试从新可执行区域执行代码可能会产生不可预知的结果。

例子

有关代码示例,请参阅 virtual2Alloc

要求

要求 价值
最低支持的客户端 Windows 10 [仅限桌面应用]
支持的最低服务器 Windows Server 2016 [仅限桌面应用]
目标平台 窗户
标头 memoryapi.h (包括 Windows.h)
WindowsApp.lib
DLL Kernel32.dll

另请参阅

内存管理功能

虚拟内存函数

VirtualAlloc

VirtualAllocEx

VirtualFree

VirtualLock

VirtualProtectFromApp

VirtualQuery