Skip to main content

XMemVirtualAlloc

在调用进程的虚拟地址空间中预留、提交或更改一个区域的页状态。
与标准 Win32 VirtualAlloc 不同,此函数分配的内存不保证会自动初始化为零。

语法

参数

BaseAddress _In_opt_
类型:PVOID
要分配的区域的起始地址。如果正在预留内存,则指定的地址会向下舍入到最接近的分配粒度的倍数(在 XBOX 上为 4K、64K 或 2MB)。如果内存已被预留且正在提交,则地址会向下舍入到下一个页边界。如果此参数为 NULL,则系统会决定在哪里分配该区域。
Size _In_
类型:SIZE_T
区域的大小(以字节为单位)。如果 BaseAddress 参数为 NULL,则此值将向上舍入到下一个页边界。否则,分配的页包含从 BaseAddress 到 BaseAddress+Size 范围内包含一个或多个字节的所有页。这意味着跨越页边界的 2 字节范围会使两个页都包含在分配的区域中。
AllocationType _In_
类型:DWORD
内存分配的类型。此参数必须包含以下值之一。 此参数还可以按如下方式指定以下值。
对于 ERA 游戏,MEM_LARGE_PAGES 表示 64K 页,而在 Windows 桌面上表示 2MB 页。由于存在歧义,该常量已在 Microsoft Game Development Kit (GDK) 中移除。

XMemFlags _In_
类型:ULONGLONG
在 XBOX 上用于获取某些专用内存类型。此参数必须包含以下值之一。 在 XBOX 上,可以分配具有受限虚拟内存地址的内存,保证不使用高位。使用以下任一值将限制地址仅使用所指示的位数。XMEM_40BIT_ADDRESS (0x00007000ULL)、XMEM_41BIT_ADDRESS (0x00006000ULL)、XMEM_42BIT_ADDRESS (0x00005000ULL)、XMEM_43BIT_ADDRESS (0x00004000ULL)、XMEM_44BIT_ADDRESS (0x00003000ULL)、XMEM_45BIT_ADDRESS (0x00002000ULL)、XMEM_46BIT_ADDRESS (0x00001000ULL)。
在 D3D12Device 创建或调用 D3DConfigureVirtualMemory 之前,无法分配图形内存。如果请求的内存对 GPU 可见,则游戏必须同时指定显式的图形页保护标志,不再有基于 CPU 页保护设置的默认值。这与之前的 XBOX OS 版本不同。
此参数还可以按如下方式指定以下值。 在 Anaconda 设备以及仿真 Anaconda 的 Dante 设备上,在使用高级游戏内存模式时,还可以应用以下参数。在所有其他情况下,将忽略这些参数。
这些标志是可选的。如果未指定,所有图形分配将默认使用 XMEM_GPU_OPTIMAL_BANDWIDTH_PREFERRED,而所有其他分配将默认使用 XMEM_STANDARD_BANDWIDTH_PREFERRED。
XMemFlags 参数包含一个可选的四字符代码标签。字符可以是 a-z、A-Z、0-9 和 $ 中的任意字符。可以使用函数 XMemMakeTag 在正确的位位置构造正确编码的标签值。该标签只能与已提交的内存区域关联,不能与预留关联。此四字符代码标签将由参数的高 24 位表示。可以通过 XMemVirtualQuery 检索该标签,并且它也会显示在 PIX 内存分析中。 示例:

PageProtection _In_
类型:DWORD
要分配的页区域的内存保护。如果正在提交页,则可以指定 内存保护常量 中的任何一个。 以下 XBOX 特定的值允许用于 PageProtection 参数,并且当指定 XMEM_GRAPHICS 或 XMEM_GRAPHICS_32BIT_ADDRESS 时必需其一。此要求与之前的 XBOX OS 版本不同。这些值也可以指定给其他内存管理函数(例如 VirtualProtect),用于以 XMEM_GRAPHICS 分配的范围内的内存地址。 此参数还可以按如下方式指定以下值。

返回值

类型:PVOID 如果函数成功,返回值是所分配的页区域的基地址。 如果函数失败,返回值为 NULL。若要获取扩展错误信息,请调用 GetLastError。

备注

每个页都有一个关联的页状态。XMemVirtualAlloc 函数可执行以下操作:
  • 提交一个预留页区域
  • 预留一个空闲页区域
  • 同时预留并提交一个空闲页区域
XMemVirtualAlloc 不能预留已预留的页。它可以提交已提交的页。这意味着你可以提交一系列页,无论它们是否已被提交,函数都不会失败。 你可以使用 XMemVirtualAlloc 预留一块页,然后再次调用 XMemVirtualAlloc 从预留块中提交单个页。这使进程能够预留虚拟地址空间的一个范围,而无需消耗物理存储,直到需要时为止。 如果 BaseAddress 参数不为 NULL,则该函数使用 BaseAddress 和 Size 参数来计算要分配的页区域。整个页范围的当前状态必须与 AllocationType 参数指定的分配类型兼容。否则,函数会失败并且不会分配任何页。如前所述,此兼容性要求并不排除提交已提交的页。 XMemVirtualAlloc 函数可用于在调用进程的虚拟地址空间中预留一个用于映射物理页的内存区域。然后,可以根据应用程序的需要将该内存区域用于将物理页映射进出虚拟内存。必须在 AllocationType 参数中设置 MEM_RESERVE 和 MEM_64K_PAGES 值;不得设置 MEM_COMMIT 值。必须在 XMemFlags 参数上设置 XMEM_MAPPABLE。以这种方式预留的地址空间通过 XMemMapPhysicalPages API 进行提交。 VirtualFree 函数可以取消提交已提交的页,释放该页的存储;或者同时取消提交并释放已提交的页。它还可以释放已预留的页,使其成为空闲页。 除了为 XBOX 特定的内存特性提供扩展外,此 API 与 VirtualAlloc 不同之处在于不保证返回的内存已初始化为零。XMemVirtualAlloc 也不保证保留先前的内存内容。游戏中 XMemVirtualAlloc 的大多数用例涉及获取图形内存(通常从零初始化中获益不大),或者为堆实现添加内存,而堆实现从零初始化中也几乎没有获得有用价值。此外,调用方在其选择的时机自行对返回的内存进行零初始化非常简单。通过不强制执行 VirtualAlloc 的这一保证,XMemVirtualAlloc 的实现具有更大的灵活性,可以提供更高的性能。 XMemVirtualAlloc 与 VirtualAlloc 还有一个不同之处:通过此 API 调用获得的内存立即可用。相比之下,VirtualAlloc 返回的内存地址只会在第一次访问时通过昂贵的缺页操作来填充物理页。 使用 XMemVirtualAlloc 分配的内存应使用 VirtualFree 释放。 PAGE_NOCACHE 和 PAGE_WRITECOMBINE 页保护标志在内存预留时固定,并且不能在稍后的提交请求期间更改。在提交内存时尝试更改这些标志之一的状态将被静默忽略。内存提交将成功,但内存将保持这些标志的原始状态。 示例:

要求

头文件: xmem.h 库: xmem.lib 支持的平台: XBOX One 系列主机和 XBOX Series 主机

另请参阅

XMem 参考
XMemMapPhysicalPages
VirtualFree
最后修改于 2026年10月5日