VirtualAlloc 函数 (memoryapi.h)

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

若要在另一个进程的地址空间中分配内存,请使用 VirtualAllocEx 函数。

语法

LPVOID VirtualAlloc(
  [in, optional] LPVOID lpAddress,
  [in]           SIZE_T dwSize,
  [in]           DWORD  flAllocationType,
  [in]           DWORD  flProtect
);

参数

[in, optional] lpAddress

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

如果此地址位于尚未通过调用 InitializeEnclave 进行初始化的 enclave 内, VirtualAlloc 会为该地址的 enclave 分配一个零页。 页面必须以前未提交,并且不会使用 Intel Software Guard 扩展编程模型的 EEXTEND 指令进行测量。

如果地址位于已初始化的 enclave 内,则分配操作会失败并 出现ERROR_INVALID_ADDRESS 错误。 对于不支持动态内存管理的 enclave ((即 SGX1) )也是如此。 SGX2 enclave 将允许分配,并且该页必须在分配后被 enclave 接受。

[in] dwSize

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

[in] flAllocationType

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

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

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

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

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

如果 lpAddress 指定 enclave 中的地址,则必须MEM_COMMITflAllocationType

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

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

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

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

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

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

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

MEM_RESET_UNDO
0x1000000
仅对之前成功应用MEM_RESET的地址范围调用 MEM_RESET_UNDO 。 它指示调用方对 lpAddressdwSize 指定的指定内存范围中的数据感兴趣,并尝试反转 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: 在Windows 8和Windows Server 2012之前,不支持MEM_RESET_UNDO标志。

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

含义
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] flProtect

要分配的页区域的内存保护。 如果正在提交页面,则可以指定任何一个 内存保护常量

如果 lpAddress 指定 enclave 中的地址, 则 flProtect 不能为以下任何值:

  • PAGE_NOACCESS
  • PAGE_GUARD
  • PAGE_NOCACHE
  • PAGE_WRITECOMBINE

为 enclave 分配动态内存时, flProtect 参数必须 PAGE_READWRITEPAGE_EXECUTE_READWRITE

返回值

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

如果函数失败,则返回值为 NULL。 要获得更多的错误信息,请调用 GetLastError。

注解

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

  • 提交保留页的区域
  • 保留可用页面区域
  • 同时保留和提交可用页面区域

VirtualAlloc 无法保留保留页。 它可以提交已提交的页面。 这意味着,无论页面是否已提交,都可以提交一系列页面,并且函数不会失败。

可以使用“VirtualAlloc”保留一个页面块,然后对“VirtualAlloc”进行其他调用,以提交保留块中的各个页面。 这使进程能够保留其虚拟地址空间的范围,而无需使用物理存储,直到需要为止。

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

若要执行动态生成的代码,请使用 VirtualAlloc 分配内存,并使用 VirtualProtect 函数授予 PAGE_EXECUTE 访问权限。

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

另请参阅

内存管理函数

虚拟内存函数

VirtualAllocEx

VirtualFree

VirtualLock

VirtualProtect

VirtualQuery

VBS enclave 中可用的 Vertdll API