VirtualAllocFromApp 函数 (memoryapi.h)

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

语法

PVOID VirtualAllocFromApp(
  [in, optional] PVOID  BaseAddress,
  [in]           SIZE_T Size,
  [in]           ULONG  AllocationType,
  [in]           ULONG  Protection
);

参数

[in, optional] BaseAddress

要分配的区域的起始地址。 如果保留内存,则指定的地址向下舍入到分配粒度中最近的倍数。 如果内存已保留并正在提交,地址将向下舍入到下一页边界。 若要确定页面的大小和主机计算机上的分配粒度,请使用 GetSystemInfo 函数。 如果此参数 NULL,系统将确定分配区域的位置。

[in] Size

区域的大小(以字节为单位)。 如果 BaseAddress 参数 NULL,则此值向上舍入到下一页边界。 否则,分配的页面将包含从 BaseAddressBaseAddress+Size范围内包含一个或多个字节的所有页。 这意味着跨页边界的 2 字节范围会导致这两个页面都包括在分配的区域。

[in] AllocationType

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

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

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

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

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

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

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

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

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

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

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

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

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

此值不能用于任何其他值。 如果在之前未 MEM_RESET 的地址范围上调用 MEM_RESET_UNDO,则行为是未定义的。 指定 MEM_RESET时,VirtualAllocFromApp 函数将忽略 Protection的值。 但是,仍必须将保护 设置为有效的保护值,例如 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] Protection

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

  • PAGE_EXECUTE
  • PAGE_EXECUTE_READ
  • PAGE_EXECUTE_READWRITE
  • PAGE_EXECUTE_WRITECOPY

返回值

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

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

言论

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

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

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

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

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

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

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

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

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

要求

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

另请参阅

内存管理功能

虚拟内存函数

VirtualAlloc

VirtualAllocEx

VirtualFree

VirtualLock

VirtualProtectFromApp

VirtualQuery