共用方式為


遊戲開發人員的64位程序設計

處理器製造商在其桌上型電腦中僅提供 64 位元處理器,甚至大多數筆記型電腦的晶片組也支援 x64 技術。 遊戲開發人員務必利用 64 位處理器為其新應用程式所提供的改進功能,並確保其先前的應用程式在新的處理器和 64 位版本的 Windows Vista 和 Windows 7 上正確執行。 本文說明相容性和移植問題,並協助開發人員輕鬆轉換至64位平臺。

Microsoft目前有下列 64 位作系統:

  • Windows 10
  • Windows 11
  • Windows Server 2019 或更新版本

過去 64 位元作業系統:

  • Windows Server 2003 Service Pack 1
  • Windows XP Professional x64 Edition (適用於 OEM 和透過 MSDN 提供給開發人員)
  • Windows Vista
  • Windows 7
  • Windows 8.0
  • Windows 8.1
  • Windows Server 2008 - 2016

注意

Windows Server 2008 R2 或更新版本僅適用於 64 位版本。 Windows 11 僅適用於 64 位或 ARM64 版本。

 

可尋址記憶體的差異

大多數開發人員注意到的第一件事是,64 位處理器在實體和虛擬記憶體的可尋址數量上提供了巨大的提升。

  • 32 位平臺上的32位應用程式最多可以處理2 GB。

  • 使用 32 位 Windows XP 或 Windows Server 2003 上的 /LARGEADDRESSAWARE:YES 連結器旗標所建置的 32 位應用程式,具有特殊 /3gb 開機選項最多可以處理 3 GB。 這隻會將核心限製為 1 GB,這可能會導致某些驅動程式和/或服務失敗。

  • 在 32 位元版本的 Windows Vista、Windows Server 2008 和 Windows 7 上,使用 /LARGEADDRESSAWARE:YES 連結器旗標建置的 32 位元應用程式,可以存取由開機組態資料 (BCD) 元素 IncreaseUserVa 所指定的記憶體數量。 IncreaseUserVa 的值範圍可以從預設的 2048 到 3072(3072 與 Windows XP 上 /3gb 開機選項所設定的記憶體數量相符)。 其餘 4 GB 會配置給核心,並可能導致驅動程式和服務組態失敗。

    如需 BCD 的詳細資訊,請參閱 開機設定資料

  • 64 位平臺上的 32 位應用程式可以尋址最多 2 GB,若使用 /LARGEADDRESSAWARE:YES 連結器旗標,則可以尋址最多 4 GB。

  • 64 位應用程式會使用 43 位進行尋址,這會為應用程式提供 8 TB 的虛擬位址,並為核心保留 8 TB。

除了記憶體之外,使用記憶體對應檔案 I/O 的 64 位應用程式也從增加的虛擬位址空間中獲益匪淺。 64 位架構也改善了浮點效能,並更快速地傳遞參數。 64 位處理器的緩存器數目是一般用途和串流 SIMD 擴充功能 (SSE) 類型的兩倍,以及 SSE 和 SSE2 指令集的支援:許多 64 位處理器甚至支援 SSE3 指令集。

在建置時指定大型規模Address-Aware

當使用連結器旗標 /LARGEADDRESSAWARE 建置 32 位元應用程式時,最好指定使應用程式能夠處理大型位址,即使該應用程式並非要在 64 位元平臺上使用,因為這樣可以免費享有額外好處。 如先前所述,為組建啟用此旗標可讓32位程式在32位作系統或64位OS上使用特殊開機選項存取更多記憶體。 不過,開發人員必須小心不要進行指標假設,例如,不要假設最高位元在 32 位指標中永遠不會被設定。 一般而言,啟用 /LARGEADDRESSAWARE 旗標是很好的作法。

具有大型位址感知的 32 位應用程式可以在運行時間透過呼叫 GlobalMemoryStatusEx 來判斷其目前 OS 設定可用的虛擬位址空間總數。 ullTotalVirtual 結果的範圍從 2147352576 個字節 (2 GB) 到 4294836224 個字節 (4 GB)。 大於 3221094400 (3 GB) 的值只能在64位版本的 Windows 上取得。 例如,如果 IncreaseUserVa 的值為 2560,則結果為 ullTotalVirtual,值為 2684223488 個字節。

64 位平臺上32位應用程式的相容性

64 位元的 Windows 作業系統與 IA32 架構具有二進位相容性,32 位元應用程式使用的大多數 API 都可以透過 Windows 64 位元模擬器,即 WOW64,來取得。 WOW64 可協助確保這些 API 如預期般運作。

WOW64 有一個執行層面,負責處理 32 位數據的封送。 WOW64 會重新導向 DLL 檔案要求、重新導向 32 位應用程式的一些登錄分支,並反映 32 位和 64 位應用程式的一些登錄分支。

如需 WOW64 的詳細資訊,請參閱 WOW64 實作詳細資料

潛在的相容性陷阱

針對 32 位平台開發的大部分應用程式都會在 64 位平臺上執行,而不會發生問題。 一些應用程式可能會有問題,這可能包括下列專案:

  • 64 位版本的 Windows作系統的所有驅動程式都必須是 64 位版本。 需要新的64位驅動程式會影響依賴舊驅動程式的複製保護配置。 請注意,內核模式驅動程序必須是 Authenticode 簽署,才能由 64 位版本的 Windows 載入。
  • 64 位進程無法載入 32 位 DLL,而 32 位進程無法載入 64 位 DLL。 開發人員必須先確定有64位版本的第三方 DLL 可供使用,才能繼續進行開發。 如果您必須在64位進程中使用32位 DLL,則可以使用Windows進程間通訊 (IPC)。 COM元件也可以使用外部進程伺服器和封送處理技術來進行跨界線的溝通,但這樣做可能會導致效能損失。
  • 許多 x64 處理器也是多核心處理器,開發人員需要測試這如何影響其舊版應用程式。 如需多核心處理器和遊戲應用程式含意的詳細資訊,請參閱 遊戲計時和多核心處理器
  • 應用程式也應該呼叫 SHGetFolderPath 來探索檔案路徑,因為某些資料夾名稱在某些情況下已變更。 例如,CSIDL_PROGRAM_FILES會針對在64位平臺上執行的32位應用程式傳回 「C:\Program Files(x86)」,而不是 「C:\Program Files」。。 開發人員必須注意 WOW64 模擬器的重新導向和反映功能如何運作。

此外,開發人員需要小心他們可能仍在使用的 16 位元程式。 WOW64 無法處理16位應用程式;這包括舊的安裝程式和所有 MS-DOS 程式。

注意

最常見的相容性問題是執行16位程式代碼,且沒有64位驅動程式進行複製保護配置的安裝程式。

 

下一節將討論有關將程式碼移植到64位元原生環境的問題,以確保舊版程式能在64位元平臺上正常運作的開發人員。 它也適用於不熟悉 64 位程式設計的開發人員。

將應用程式移植到64位平臺

擁有正確的工具和連結庫有助於簡化從32位到64位開發的轉換。 DirectX 9 SDK 有連結庫來支援 x86 和 x64 型專案。 Microsoft Visual Studio 2005 和 Visual Studio 2008 同時支援 x86 和 x64 的程式代碼產生,且隨附已針對產生 x64 程式代碼優化的連結庫。 不過,開發人員也必須將 Visual C++ 執行階段隨其應用程式一起散發。 請注意,Visual Studio 2005 和 Visual Studio 2008 的 Express 版本不包含 x64 編譯程式,但 Standard、Professional 和 Team System 版本全都執行。

以 32 位平臺為目標的開發人員可以準備 64 位開發,以便稍後更容易進行轉換。 編譯 32 位專案時,開發人員應該使用 /Wp64 旗標,這會導致產生會影響可移植性之問題的警告。 一開始,切換至 64 位工具和連結庫可能會產生許多新的建置錯誤:因此,建議您先切換位中性工具和連結庫,並在切換至64位組建之前更正任何警告。

不過,變更工具、變更連結庫,以及使用特定編譯程式旗標是不夠的。 必須重新評估程式代碼標準中的假設,以確保目前的編碼標準不允許可移植性問題。 可移植性問題可能包括指標截斷、數據類型的大小和對齊方式、依賴 32 位 DLL、使用舊版 API、元件程式代碼和舊二進位檔。

注意

Visual C++ 2010 或更新版本包含 stdint.h 和 cstdint C99 標頭,定義標準可移植性類型int32_t、uint32_t、int64_t、uint64_t、intptr_t和uintptr_t。 使用這些和標準的 ptrdiff_t 和 size_t 數據類型相比於下文提到的 Windows 可移植性類型,可能更適合用來提升程式碼的可移植性。

 

主要移植問題包括:

指標截斷

指標在64位元作業系統上是64位元,因此將指標轉換成其他資料類型可能會導致數據截斷,而指標運算可能會導致資料損壞。 使用 /Wp64 旗標通常會提供這類問題的警告,但在轉換指標類型時,使用多型類型(INT_PTR、DWORD_PTR、SIZE_T、UINT_PTR等等),有助於避免此問題。 由於指標在新平臺上為64位,因此開發人員應該檢查指標的順序,以及類別和結構中的數據類型,以減少或消除填補。

數據類型和二進位檔

雖然指標在64位平臺上從32位增加到64位,但其他數據類型則不會。 固定精確度數據類型(DWORD32、DWORD64、INT32、INT64、LONG32、LONG64、UINT32、UINT64)可用於必須知道數據類型大小的位置:例如,在二進位文件結構中。 指標大小和數據對齊的變更需要特殊處理,以確保 32 位對 64 位相容性。 如需詳細資訊,請參閱 新的數據類型中的資訊。

舊版 Win32 API 和數據對齊

某些 Win32 API 已被取代,並取代為更中性 API 呼叫,例如 SetWindowLongPtr 取代 SetWindowLong。

與 x86 平臺相比,x64 平臺上不對齊存取的性能懲罰更大。 TYPE_ALIGNMENT(t)和 FIELD_OFFSET(t, member)巨集可用來判斷可供程式碼直接使用的對齊資訊。 正確使用這些上述巨集應該消除潛在的不對齊存取處罰。

如需TYPE_ALIGNMENT巨集、FIELD_OFFSET巨集和一般 64 位程式設計資訊的詳細資訊,請參閱 64 位 Windows 程式設計:移轉秘訣:使用指標的其他考慮規則

元件程式代碼

在 64 位平臺上不支援內嵌組合語言程式碼,需要將其替換。 架構中的變更可能會變更應用程式瓶頸,而 C/C++ 或內部函數可以使用更容易閱讀的程式代碼來達成類似的結果。 最建議的做法就是將所有組合語言程式碼切換至 C 或 C++。 內建函數可用來取代組合語言代碼,但應只在執行完整分析和性能分析後才使用。

x87、MMX 和 3DNow! 指令集在64位模式中已被取代。 為了 32 位模式的回溯相容性,指令集依然存在;然而,為了避免未來出現相容性問題,不建議在目前和未來的專案中使用這些指令集。

已淘汰的 API

已針對 64 位原生應用程式捨棄一些較舊的 DirectX API:DirectPlay 4 和更早版本、DirectDraw 6 和更早版本、Direct3D 8 和更早版本,以及 DirectInput 7 和更早版本。 此外,DirectMusic 的核心 API 可供原生 64 位應用程式使用,但效能層和 DirectMusic Producer 已被取代。

Visual Studio 會發出棄用警告,而且這些變更對使用最新 API 的開發人員來說不是問題。

移植應用程式的分析與優化

所有開發人員都需要重新分析任何要移植到新架構的應用程式。 許多應用程式會移植到64位平臺,其效能配置檔會與其32位版本不同。 開發人員必須先執行64位效能測試,才能評估需要優化的專案。 好消息是,許多傳統優化在64位平臺上運作。 此外,64 位編譯程式也可以使用正確的編譯程式旗標和編碼提示來執行許多優化。

某些結構可能會重新排列其內部數據類型,以節省記憶體空間並改善快取。 在某些情況下,可以使用陣列索引,而不是完整的64位指標。 /fp:fast 旗標可以改善浮點優化和向量化。 使用 __restrict、declspec(restrict) 和 declspec(noalias) 可協助編譯程式解析別名,並改善緩存器檔案的使用。

如需更多有關 /fp:fast 的資訊,請參閱 /fp(指定 Floating-Point 行為)

如需有關__restrict的更多詳細資訊,請參閱 Microsoft-Specific 修飾詞

如需 declspec(restrict) 的詳細資訊,請參閱 優化最佳做法

如需 declspec(noalias) 的詳細資訊,請參閱 __declspec(noalias)

64 位元作業系統上的托管程式碼

許多遊戲開發人員在其工具鏈中使用受控代碼,因此瞭解它在64位操作系統上的運作方式會很有幫助。 受管理代碼具有指令集中立性,因此當您在 64 位元作業系統上執行受管理應用程式時,Common Language Runtime (CLR) 可以將其作為 32 位元或 64 位元的處理程序執行。 根據預設,CLR 會以 64 位的形式執行 Managed 應用程式,而且它們應該正常運作,且沒有任何問題。 不過,如果您的應用程式相依於原生 32 位的 DLL,則應用程式在嘗試呼叫此 DLL 時將會失敗。 64 位進程需要完全 64 位的程式代碼,而且 32 位 DLL 無法從 64 位進程呼叫。 最好的長期解決方案是將原生程式代碼編譯為64位,但一個完全合理的短期解決方案是只使用 /platform:x86 組建旗標,將受控應用程式標示為 x86。

執行64位作系統的效能影響

由於具有 AMD64 和 Intel 64 架構的處理器可以原生執行 32 位指令,因此它們可以全速執行 32 位應用程式,即使是在 64 位作系統上也一樣。 呼叫作系統函式時,在32位和64位之間轉換參數的成本不大,但這項成本通常可忽略。 這表示在 64 位作系統上執行 32 位應用程式時,您應該不會看到速度變慢。

當您將應用程式編譯為64位時,計算會變得更複雜。 64 位程式使用 64 位指標,其指令稍微較大,因此記憶體需求會稍微增加。 這可能會導致效能略有下降。 另一方面,在單一指令中擁有兩倍的暫存器以及執行64位整數計算的能力,往往可以大大彌補其他不足。 淨結果是,64 位應用程式的執行速度可能會比編譯為32位的相同應用程式稍微慢一點,但通常會執行稍微快一點。

總結

六十四位元架構使開發人員能突破遊戲外觀、音效以及遊戲體驗上的限制。 不過,從32位程式設計轉換為64位程序設計並不簡單。 藉由瞭解這兩者之間的差異,以及使用最新的工具,轉換至64位平臺會更容易且更快。

如需 64 位程式設計的詳細資訊,請參閱 Visual C++ 開發人員中心 :64 位程式設計