VirtualAllocEx 函数 (memoryapi.h)
保留、提交或更改指定进程的虚拟地址空间中内存区域的状态。 该函数初始化它分配给零的内存。
若要为物理内存指定 NUMA 节点,请参阅 virtualAllocExNuma
语法
LPVOID VirtualAllocEx(
[in] HANDLE hProcess,
[in, optional] LPVOID lpAddress,
[in] SIZE_T dwSize,
[in] DWORD flAllocationType,
[in] DWORD flProtect
);
参数
[in] hProcess
进程的句柄。 该函数在进程的虚拟地址空间中分配内存。
句柄必须具有 PROCESS_VM_OPERATION 访问权限。 有关详细信息,请参阅 进程安全性和访问权限。
[in, optional] lpAddress
为要分配的页面区域指定所需起始地址的指针。
如果要保留内存,该函数会将此地址舍入到分配粒度中最近的倍数。
如果要提交已保留的内存,函数会将此地址向下舍入到最近的页面边界。 若要确定页面的大小和主机计算机上的分配粒度,请使用 GetSystemInfo 函数。
如果 lpAddressNULL,则该函数将确定分配区域的位置。
如果此地址位于未通过调用 InitializeEnclave初始化的 enclave 中,VirtualAllocEx 为该地址的 enclave 分配零页。 该页必须以前未提交,并且不会使用 Intel Software Guard Extensions 编程模型的 EEXTEND 指令进行测量。
如果初始化的 enclave 中的地址,则分配操作将失败,并出现 ERROR_INVALID_ADDRESS 错误。 对于不支持动态内存管理的 enclave(即 SGX1),这是事实。 SGX2 enclave 将允许分配,并且该页必须在分配后由 enclave 接受。
[in] dwSize
要分配的内存区域的大小(以字节为单位)。
如果 lpAddressNULL,则该函数将 dwSize 向上舍入到下一页边界。
如果 lpAddress 未 NULL,则该函数会将包含一个或多个字节的所有页面分配给从 lpAddress 到 lpAddress+dwSize。 例如,这意味着跨页边界的 2 字节范围会导致函数分配这两个页面。
[in] flAllocationType
内存分配的类型。 此参数必须包含以下值之一。
价值 | 意义 |
---|---|
|
为指定的保留内存页分配内存费用(从内存的总体大小和磁盘上的分页文件)。 该函数还保证当调用方稍后最初访问内存时,内容将为零。 除非实际访问虚拟地址/直到实际访问虚拟地址,否则不会分配实际物理页。
若要在一个步骤中保留和提交页面,请使用 除非已保留整个范围,否则尝试通过指定不带 MEM_RESERVE 的 MEM_COMMIT 并NULLlpAddress 来提交特定地址范围。 生成的错误代码 ERROR_INVALID_ADDRESS。 尝试提交已提交的页面不会导致函数失败。 这意味着可以提交页面,而无需首先确定每个页面的当前承诺状态。 如果 lpAddress 指定 enclave 中的地址,则必须 MEM_COMMITflAllocationType。 |
|
保留进程的虚拟地址空间范围,而无需在内存或磁盘上的分页文件中分配任何实际物理存储。
使用 MEM_COMMIT再次调用 virtualAllocEx,提交保留页。 若要在一个步骤中保留和提交页面,请使用 其他内存分配函数(如 malloc 和 LocalAlloc)在释放之前无法使用保留内存。 |
|
指示 lpAddress 指定的内存区域中的数据不再感兴趣,dwSize 不再感兴趣。 不应从分页文件读取或写入页面。 但是,内存块稍后将再次使用,因此不应将其取消提交。 此值不能用于任何其他值。
使用此值不能保证使用 MEM_RESET 操作的范围将包含零。 如果希望该区域包含零,请取消提交内存,然后重新提交内存。 使用 MEM_RESET时,VirtualAllocEx 函数将忽略 fProtect的值。 但是,仍必须将 fProtect 设置为有效的保护值,例如 PAGE_NOACCESS。 VirtualAllocEx 如果使用 MEM_RESET 并且内存范围映射到文件,则返回错误。 仅当共享视图映射到分页文件时,才可接受。 |
|
MEM_RESET_UNDO 只应在之前成功应用 MEM_RESET 的地址范围上调用。 它指示由 lpAddress 指定的指定内存范围中的数据 和 dwSize 对调用方感兴趣,并尝试扭转 MEM_RESET的影响。 如果函数成功,则表示指定地址范围中的所有数据都保持不变。 如果函数失败,则地址范围中的至少一些数据已替换为零。
此值不能用于任何其他值。 如果在之前未 MEM_RESET 的地址范围上调用 MEM_RESET_UNDO,则行为是未定义的。 指定 MEM_RESET时,VirtualAllocEx 函数将忽略 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 标志。 |
此参数还可以按指示指定以下值。
价值 | 意义 |
---|---|
|
使用 大型页面支持分配内存。
大小和对齐方式必须是大页最小值的倍数。 若要获取此值,请使用 GetLargePageMinimum 函数。 如果指定此值,还必须指定 MEM_RESERVE 和 MEM_COMMIT。 |
|
保留可用于映射 地址窗口扩展插件(AWE)页的地址范围。
此值必须与 MEM_RESERVE 一起使用,并且不能用于其他值。 |
|
以最高可能地址分配内存。 这比常规分配要慢,尤其是在分配很多时。 |
[in] flProtect
要分配的页面区域的内存保护。 如果要提交页面,则可以指定
如果 lpAddress 指定 enclave 中的地址,flProtect 不能是以下值之一:
- PAGE_NOACCESS
- PAGE_GUARD
- PAGE_NOCACHE
- PAGE_WRITECOMBINE
为 enclave 分配动态内存时,flProtect 参数必须 PAGE_READWRITE 或 PAGE_EXECUTE_READWRITE。
返回值
如果函数成功,则返回值是页面分配区域的基址。
如果函数失败,则返回值 NULL。 若要获取扩展的错误信息,请调用 GetLastError。
言论
每个页面都有一个关联的 页面状态。 virtualAllocEx 函数
- 提交保留页的区域
- 保留免费页面的区域
- 同时保留并提交一个免费页面区域
可以使用 VirtualAllocEx 来保留页面块,然后对 virtualAllocEx 进行其他调用,以提交保留块中的单个页面。 这样一个进程就可以保留其虚拟地址空间的范围,而无需消耗物理存储,直到需要它。
如果 lpAddress 参数未 NULL,则该函数将使用 lpAddress,dwSize 参数来计算要分配的页面区域。 整个页面范围的当前状态必须与 flAllocationType 参数指定的分配类型兼容。 否则,该函数将失败,并且未分配任何页面。 此兼容性要求不排除提交已提交的页面;请参阅前面的列表。
若要执行动态生成的代码,请使用 VirtualAllocEx 来分配内存和 VirtualProtectEx 函数来授予 PAGE_EXECUTE 访问权限。
VirtualAllocEx 函数可用于在指定进程的虚拟地址空间中保留内存 地址窗口扩展(AWE)区域。 然后,可以使用此内存区域根据应用程序的要求将物理页映射到虚拟内存中和传出虚拟内存。 必须在 AllocationType 参数中设置 MEM_PHYSICAL 和 MEM_RESERVE 值。 不能设置 MEM_COMMIT 值。 页面保护必须设置为 PAGE_READWRITE。
VirtualFreeEx 函数可以取消提交页面、释放页面的存储,也可以同时取消提交和释放已提交的页面。 它还可以释放保留页,使其成为免费页面。
创建可执行的区域时,调用程序负责确保在代码设置到位后通过适当的调用 FlushInstructionCache 缓存一致性。 否则,尝试从新可执行区域执行代码可能会产生不可预知的结果。
要求
要求 | 价值 |
---|---|
最低支持的客户端 | Windows XP [桌面应用 |UWP 应用] |
支持的最低服务器 | Windows Server 2003 [桌面应用 |UWP 应用] |
目标平台 | 窗户 |
标头 | memoryapi.h (包括 Windows.h、Memoryapi.h) |
库 | onecore.lib |
DLL | Kernel32.dll |
另请参阅
反馈
https://aka.ms/ContentUserFeedback。
即将发布:在整个 2024 年,我们将逐步淘汰作为内容反馈机制的“GitHub 问题”,并将其取代为新的反馈系统。 有关详细信息,请参阅:提交和查看相关反馈