> ## Documentation Index
> Fetch the complete documentation index at: https://devdocs.xbox.com/llms.txt
> Use this file to discover all available pages before exploring further.

# XMemVirtualAlloc

> XMemVirtualAlloc

# XMemVirtualAlloc

保留、認可或變更呼叫處理序之虛擬位址空間中某個分頁區域的狀態。

<Note>
  與標準 Win32 <a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc" target="_blank">VirtualAlloc</a> 不同，此函式所配置的記憶體\_不\_保證會自動初始化為零。
</Note>

## 語法

```cpp theme={null}
PVOID XMemVirtualAlloc(  
         PVOID BaseAddress,  
         SIZE_T Size,  
         DWORD AllocationType,  
         ULONGLONG XMemFlags,  
         DWORD PageProtection  
)  
```

### 參數

*BaseAddress*   \_In\_opt\_<br />類型：PVOID

要配置之區域的起始位址。如果正在保留記憶體，指定的位址會無條件捨去至配置細微度 (在 XBOX 上為 4K、64K 或 2MB) 最接近的倍數。如果記憶體已保留且正在認可，則位址會無條件捨去至下一個分頁邊界。如果此參數為 NULL，系統會決定要在何處配置區域。

<br />

*Size*   \_In\_<br />類型：SIZE\_T

區域的大小 (以位元組為單位)。如果 *BaseAddress* 參數為 NULL，此值會無條件進位到下一個分頁邊界。否則，配置的分頁會包含在 *BaseAddress* 到 *BaseAddress*+*Size* 範圍內含有一或多個位元組的所有分頁。這表示跨越分頁邊界的 2 位元組範圍會導致兩個分頁都包含在配置的區域中。

<br />

*AllocationType*   \_In\_<br />類型：DWORD

記憶體配置的類型。此參數必須包含下列其中一個值。

| 值 | 意義 | |
| - | - | - |
| **MEM\_COMMIT**<br />0x00001000 | 為指定的保留記憶體分頁配置記憶體費用 (從記憶體的整體大小中扣除)。若要一步完成保留和認可分頁，請以 \`MEM\_COMMIT | MEM\_RESERVE\` 呼叫 **XMemVirtualAlloc**。<br />除非整個範圍都已保留，否則嘗試透過指定 **MEM\_COMMIT** (不含 **MEM\_RESERVE**) 和非 NULL 的 *BaseAddress* 來認可特定位址範圍將會失敗。產生的錯誤碼為 **ERROR\_INVALID\_ADDRESS**。<br />嘗試認可已認可的分頁不會導致函式失敗。這表示您可以認可分頁，而不需要先判斷每個分頁目前的認可狀態。 |
| **MEM\_RESERVE**<br />0x00002000 | 保留處理序虛擬位址空間的範圍，而不在記憶體中配置任何實際的實體儲存體。您可以在後續呼叫 **XMemVirtualAlloc** 函式時認可保留的分頁，或使用 **XMemMapPhysicalPages** 直接對應實體分頁。<br />其他記憶體配置函式 (例如 **malloc** 和 **new**) 在保留的記憶體範圍釋放之前無法使用該範圍。 <br /><br />請注意，XBOX 上 *Microsoft Game Development Kit (GDK)* 中的新記憶體管理員需要在保留時設定分頁保護和快取一致性，這是與舊版 XBOX OS 不同之處。 | |
| **MEM\_RESERVE\_PLACEHOLDER**<br />0x00040000 | 預留位置會保留虛擬位址，但不會將 VA 鎖定為特定的分頁大小或分頁保護。分頁大小和分頁保護會在使用 **MEM\_REPLACE\_PLACEHOLDER** 以實際保留或認可取代預留位置時選取。若要建立預留位置，請以 **MEM\_RESERVE \| MEM\_RESERVE\_PLACEHOLDER** 呼叫 **XMemVirtualAlloc**，並將 PageProtection 設定為 **PAGE\_NOACCESS**。使用 **MEM\_RESERVE\_PLACEHOLDER** 一律會傳回 2MB 對齊的位址，以確保日後可與 **MEM\_2MB\_PAGES** 搭配使用。不過，一旦保留之後，便可使用 VirtualFree 搭配 **MEM\_RELEASE \| MEM\_PRESERVE\_PLACEHOLDER**，以任何細微度 (4K、64K 或 2MB) 分割預留位置。 | |
| **MEM\_REPLACE\_PLACEHOLDER**<br />0x00004000 | 以一般私人配置取代預留位置。取代預留位置時，BaseAddress 和 Size 必須與預留位置的值完全相符。以私人配置取代預留位置後，若要將該配置釋放回預留位置，請參閱 **VirtualFree** 和 **VirtualFreeEx** 的 **dwFreeType** 參數。 | |

此參數也可以指定下列值，如下所示。

| 值 | 意義 |
| - | - |
| **MEM\_2MB\_PAGES**<br />0x20000000 | 指定 2MB 的分頁大小。 |
| **MEM\_64K\_PAGES**<br />0x20400000 | 指定 64K 的分頁大小。 |

<Note>
  對於 ERA 遊戲，**MEM\_LARGE\_PAGES** 代表 64K 分頁，而在 Windows 桌面上代表 2MB 分頁。由於有此歧義，*Microsoft Game Development Kit (GDK)* 已將其移除。
</Note>

<br />

*XMemFlags*   \_In\_<br />類型：ULONGLONG

在 XBOX 上用來取得特定的特殊記憶體類型。此參數必須包含下列其中一個值。

| 值 | 意義 |
| - | - |
| **XMEM\_CPU**<br />0x00000001 | 配置只有 CPU 可存取的記憶體。 |
| **XMEM\_GRAPHICS**<br />0x00000003 | 配置 CPU 和 GPU 都可存取的記憶體。任何以 **XMEM\_GRAPHICS** 認可的記憶體都會對應到 GPU 的分頁表中。 |
| **XMEM\_GRAPHICS\_32BIT\_ADDRESS**<br />0x00000007 | 指定自動指派的位址位於位址空間的低 4GB 中。使用此旗標認可的記憶體也可供 GPU 存取。 |

在 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)。

<Note>
  在建立 D3D12Device 或呼叫 D3DConfigureVirtualMemory 之前，無法配置圖形記憶體。如果要求的記憶體將對 GPU 可見，遊戲\_必須\_同時指定明確的圖形分頁保護旗標，不再有依據 CPU 分頁保護設定的預設值。這是與舊版 XBOX OS 不同之處。
</Note>

此參數也可以指定下列值，如下所示。

| 值 | 意義 |
| - | - |
| **XMEM\_TOOL**<br />0x00000010 | 指定配置計入工具分割區，而非遊戲分割區。此旗標需要在 *AllocationType* 參數上指定 **MEM\_2MB\_PAGES** 或 **MEM\_64K\_PAGES**。 |
| **XMEM\_MAPPABLE**<br />0x00000020 | 指定配置是要透過 [XMemMapPhysicalPages](/zh-TW/reference/system/xmem/functions/xmemmapphysicalpages) 用於實體分頁對應的位址保留。此旗標需要在 *AllocationType* 參數上指定 **MEM\_RESERVE** 以及 **MEM\_2MB\_PAGES** 或 **MEM\_64K\_PAGES**。 |

在 Anaconda 裝置以及模擬 Anaconda 的 Dante 裝置上，使用進階遊戲記憶體模式時，也可以套用下列參數。在所有其他情況下，這些參數都會被忽略。

<Note>
  這些旗標是選擇性的。如果未指定，所有圖形配置預設都會使用 XMEM\_GPU\_OPTIMAL\_BANDWIDTH\_PREFERRED，而所有其他配置預設都會使用 XMEM\_STANDARD\_BANDWIDTH\_PREFERRED。
</Note>

| 值 | 意義 |
| - | - |
| **XMEM\_STD\_BW\_REQ** 或 <br />**XMEM\_STANDARD\_BANDWIDTH\_REQUIRED**<br />0x00000080 | 指定配置必須使用標準頻寬記憶體來滿足。 |
| **XMEM\_STD\_BW\_PREF** 或 <br />**XMEM\_STANDARD\_BANDWIDTH\_PREFERRED**<br />0x00000180 | 指定配置應優先使用標準頻寬記憶體，只有在標準頻寬記憶體耗盡時才使用 GPU 最佳頻寬記憶體。 |
| **XMEM\_GPU\_OPTBW\_REQ** 或 <br />**XMEM\_GPU\_OPTIMAL\_BANDWIDTH\_REQUIRED**<br />0x00000280 | 指定配置必須使用 GPU 最佳頻寬記憶體來滿足。 |
| **XMEM\_GPU\_OPTBW\_PREF** 或 <br />**XMEM\_GPU\_OPTIMAL\_BANDWIDTH\_PREFERRED**<br />0x00000380 | 指定配置應優先使用 GPU 最佳頻寬記憶體，只有在 GPU 最佳頻寬記憶體耗盡時才使用標準頻寬記憶體。 |

*XMemFlags* 參數包含選擇性的四字元代碼標籤。字元可以是 a-z、A-Z、0-9 和 \$ 中的任一字元。可使用 [XMemMakeTag](/zh-TW/reference/system/xmem/functions/xmemmaketag) 函式，在正確的位元位置建構正確編碼的標籤值。標籤只能與已認可的記憶體區域建立關聯，而不能與保留建立關聯。此四字元代碼標籤會由參數的高 24 位元表示。標籤可透過 [XMemVirtualQuery](/zh-TW/reference/system/xmem/functions/xmemvirtualquery) 擷取，也會顯示在 PIX 記憶體分析中。

範例：

```cpp theme={null}
PVOID mem = XMemVirtualAlloc(NULL, size, MEM_64K_PAGES | MEM_COMMIT, XMemMakeTag('Fred') | XMEM_CPU, PAGE_READWRITE);
```

<br />

*PageProtection*   \_In\_<br />類型：DWORD

要配置之分頁區域的記憶體保護。如果正在認可分頁，您可以指定任一 <a href="https://learn.microsoft.com/en-us/windows/desktop/Memory/memory-protection-constants">記憶體保護常數</a>。

*PageProtection* 參數允許使用下列 XBOX 專屬值，且指定 **XMEM\_GRAPHICS** 或 **XMEM\_GRAPHICS\_32BIT\_ADDRESS** 時必須指定其中一個值。此需求是與舊版 XBOX OS 不同之處。對於以 **XMEM\_GRAPHICS** 配置之範圍內的記憶體位址，這些值也可以指定給其他記憶體管理函式 (例如 <a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualprotect">VirtualProtect</a>)。

| 值 | 意義 |
| - | - |
| **PAGE\_GRAPHICS\_NOACCESS**<br />0x0800 | 指定記憶體在 GPU 上無法存取。 |
| **PAGE\_GRAPHICS\_READONLY**<br />0x1000 | 指定記憶體在 GPU 上為唯讀。 |
| **PAGE\_GRAPHICS\_READWRITE**<br />0x2000 | 指定記憶體在 GPU 上為可讀寫。 |
| **PAGE\_GRAPHICS\_EXECUTE**<br />0x4000<br /><br />**GRAPHICS\_EXECUTE\_READ**<br />0x8000<br /><br />**PAGE\_GRAPHICS\_EXECUTE\_READWRITE**<br />0x10000 | 指定記憶體在 GPU 上為可執行。命令緩衝區需要此設定。 |

此參數也可以指定下列值，如下所示。

| 值 | 意義 |
| - | - |
| **PAGE\_GRAPHICS\_COHERENT**<br />0x20000 | 指定與 GPU 共用的記憶體在 CPU 和 GPU 快取之間會保持一致。 |
| **PAGE\_GRAPHICS\_NOCACHE**<br />0x40000 | 指定 GPU 存取記憶體時不會快取記憶體。此旗標僅適用於 XBOX Series X\|S 主機。 |

### 傳回值

類型：PVOID

如果函式成功，傳回值為所配置分頁區域的基底位址。

如果函式失敗，傳回值為 **NULL**。若要取得延伸錯誤資訊，請呼叫 <a href="https://msdn.microsoft.com/library/windows/desktop/ms679360(v=vs.85).aspx">GetLastError</a>。

## 備註

每個分頁都有相關聯的 <a href="https://learn.microsoft.com/en-us/windows/desktop/Memory/page-state">分頁狀態</a>。**XMemVirtualAlloc** 函式可以執行下列作業：

* 認可保留分頁的區域
* 保留可用分頁的區域
* 同時保留和認可可用分頁的區域

**XMemVirtualAlloc** 無法保留已保留的分頁。它可以認可已認可的分頁。這表示您可以認可某個範圍的分頁，無論這些分頁是否已認可，函式都不會失敗。

您可以使用 **XMemVirtualAlloc** 保留一個分頁區塊，然後再呼叫 **XMemVirtualAlloc** 來認可保留區塊中的個別分頁。這可讓處理序保留其虛擬位址空間的範圍，而在需要之前不會耗用實體儲存體。

如果 *BaseAddress* 參數不是 **NULL**，函式會使用 *BaseAddress* 和 *Size* 參數來計算要配置的分頁區域。整個分頁範圍目前的狀態必須與 *AllocationType* 參數所指定的配置類型相容。否則，函式會失敗，且不會配置任何分頁。如前所述，此相容性需求並不排除認可已認可的分頁。

**XMemVirtualAlloc** 函式可用於在呼叫處理序的虛擬位址空間內保留指定用來對應實體分頁的記憶體區域。接著，此記憶體區域便可依應用程式的需要，用來將實體分頁對應進出虛擬記憶體。必須在 *AllocationType* 參數中設定 **MEM\_RESERVE** 和 **MEM\_64K\_PAGES** 值；不得設定 **MEM\_COMMIT** 值。必須在 *XMemFlags* 參數上設定 **XMEM\_MAPPABLE**。以此方式保留的位址空間是使用 [XMemMapPhysicalPages](/zh-TW/reference/system/xmem/functions/xmemmapphysicalpages) API 來認可。

<a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualfree">VirtualFree</a> 函式可以解除認可已認可的分頁並釋放該分頁的儲存體，也可以同時解除認可並釋放已認可的分頁。它也可以釋放保留的分頁，使其成為可用分頁。

除了提供 XBOX 專屬記憶體特性的延伸之外，此 API 與 <a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc">VirtualAlloc</a> 的差異在於，它不強制保證傳回的記憶體會初始化為零。**XMemVirtualAlloc** 也不保證會保留先前的記憶體內容。遊戲中 **XMemVirtualAlloc** 的大多數使用案例涉及取得圖形記憶體 (通常不會因初始化為零而受益)，或將記憶體新增至堆積實作 (從零初始化中獲得的實用價值很少)。此外，呼叫端可以輕易地在自己選擇的時間實作將傳回的記憶體初始化為零。由於不強制 <a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc">VirtualAlloc</a> 的這項保證，**XMemVirtualAlloc** 的實作有更大的彈性，能夠提供更高的效能。

**XMemVirtualAlloc** 與 <a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc">VirtualAlloc</a> 的另一個差異在於，透過此 API 呼叫取得的記憶體可以立即使用。相較之下，<a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualalloc">VirtualAlloc</a> 傳回的記憶體位址只會在第一次存取時，透過代價高昂的分頁錯誤作業填入實體分頁。

以 **XMemVirtualAlloc** 配置的記憶體應使用 <a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualfree">VirtualFree</a> 釋放。

**PAGE\_NOCACHE** 和 **PAGE\_WRITECOMBINE** 分頁保護旗標會在記憶體保留時固定，無法在之後的認可要求期間變更。認可記憶體時嘗試變更這些旗標其中之一的狀態，將會被無聲地忽略。記憶體認可會成功，但記憶體的這些旗標仍會保持原始狀態。

範例：

```cpp theme={null}
// Allocate standard CPU only memory, using default (4K) pages
PVOID cpuMemory = XMemVirtualAlloc (NULL,
                                    1024 * 1024,
                                    MEM_RESERVE | MEM_COMMIT,
                                    XMEM_CPU,
                                    PAGE_READWRITE);
```

```cpp theme={null}
// Allocate 1MB of tooling memory using 64K pages
PVOID cpu64kmemory = XMemVirtualAlloc (NULL,
                                       1024 * 1024,
                                       MEM_64K_PAGES | MEM_RESERVE | MEM_COMMIT,
                                       XMEM_TOOL | XMEM_CPU,
                                       PAGE_READWRITE);
```

```cpp theme={null}
// Allocate 2MB graphics memory
PVOID gfx64kmemory = XMemVirtualAlloc (NULL,
                                       2 * 1024 * 1024,
                                       MEM_2MB_PAGES | MEM_RESERVE | MEM_COMMIT,
                                       XMEM_GRAPHICS,
                                       PAGE_READWRITE | PAGE_GRAPHICS_READONLY);
```

```cpp theme={null}
// Allocate 1MB of graphics memory using 64K pages in 32b address space
PVOID gfxmemory32b = XMemVirtualAlloc (NULL,
                                       1024 * 1024,
                                       MEM_64K_PAGES | MEM_RESERVE | MEM_COMMIT,
                                       XMEM_GRAPHICS_32BIT_ADDRESS,
                                       PAGE_READONLY | PAGE_GRAPHICS_READWRITE);
```

```cpp theme={null}
// Reserve 1GB of CPU visible VA space using 64K pages
PVOID cpuReserve = XMemVirtualAlloc (NULL,
                                     1024 * 1024 * 1024,
                                     MEM_64K_PAGES | MEM_RESERVE,
                                     XMEM_CPU,
                                     PAGE_READWRITE);

// Now commit the first 2MB of the reservation
PVOID cpuCommit = XMemVirtualAlloc (cpuReserve,
                                    2 * 1024 * 1024,
                                    MEM_COMMIT,
                                    XMEM_CPU,
                                    PAGE_READWRITE);
```

```cpp theme={null}
// Reserve 4MB of visible VA space intended for direct physical page mapping
// Note that physical pages are always 64KB and this reservation assumes
// any allocations will be in 32 or 64 page (2MB\4MB) blocks
PVOID physicalReserve = XMemVirtualAlloc (NULL,
                                          4 * 1024 * 1024,
                                          MEM_2MB_PAGES | MEM_RESERVE,
                                          XMEM_GRAPHICS | XMEM_MAPPABLE,
                                          PAGE_READONLY | PAGE_GRAPHICS_COHERENT | PAGE_GRAPHICS_READWRITE);
```

## 需求

**標頭：** xmem.h

**程式庫：** xmem.lib

**支援的平台：** XBOX One 系列主機和 XBOX Series 主機

## 另請參閱

[XMem 參考](/zh-TW/reference/system/xmem/xmem_members)<br />[XMemMapPhysicalPages](/zh-TW/reference/system/xmem/functions/xmemmapphysicalpages)<br /><a href="https://learn.microsoft.com/en-us/windows/desktop/api/memoryapi/nf-memoryapi-virtualfree">VirtualFree</a>


## Related topics

- [Working with the Microsoft GDK Game OS memory manager](/build/console-features/memory/system-memory-working.md)
- [Trabajo con el administrador de memoria del sistema operativo de juego del Microsoft GDK](/es/build/console-features/memory/system-memory-working.md)
- [使用 Microsoft GDK 游戏 OS 内存管理器](/zh-CN/build/console-features/memory/system-memory-working.md)
- [Microsoft GDK Game OS 메모리 관리자 사용](/ko/build/console-features/memory/system-memory-working.md)
- [Microsoft GDK ゲーム OS メモリ マネージャーの使用](/ja-jp/build/console-features/memory/system-memory-working.md)
