VirtualAllocFromApp 函数 (memoryapi.h)

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

语法

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

parameters

[in, optional] BaseAddress

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

[in] Size

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

[in] AllocationType

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

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

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

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

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

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

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

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

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

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

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

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

MEM_RESET_UNDO
0x1000000
仅对之前成功应用MEM_RESET的地址范围调用 MEM_RESET_UNDO 。 它指示 由 BaseAddressSize 指定的内存范围中的数据对调用方感兴趣,并尝试反转 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,则该函数使用 BaseAddressSize 参数来计算要分配的页面区域。 整个页面范围的当前状态必须与 AllocationType 参数指定的分配类型兼容。 否则,函数将失败,并且不会分配任何页面。 如前所述,此兼容性要求不排除提交已提交的页面。

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

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

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

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

要求

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

另请参阅

内存管理函数

虚拟内存函数

VirtualAlloc

VirtualAllocEx

VirtualFree

VirtualLock

VirtualProtectFromApp

VirtualQuery