64-Bit-Programmierung für Spieleentwickler
Prozessorhersteller versenden ausschließlich 64-Bit-Prozessoren auf ihren Desktopcomputern, und sogar die Chipsätze der meisten Laptop-Computer unterstützen x64-Technologie. Für Spieleentwickler ist es wichtig, die Verbesserungen zu nutzen, die 64-Bit-Prozessoren mit ihren neuen Anwendungen bieten, und sicherzustellen, dass ihre früheren Anwendungen auf den neuen Prozessoren und den 64-Bit-Editionen von Windows Vista und Windows 7 ordnungsgemäß ausgeführt werden. In diesem Artikel werden Kompatibilitäts- und Portierungsprobleme behandelt und Entwickler beim Übergang zu 64-Bit-Plattformen unterstützt.
Microsoft verfügt derzeit über die folgenden 64-Bit-Betriebssysteme:
- Windows 10
- Windows 11
- Windows Server 2019 oder höher
Frühere 64-Bit-Betriebssysteme:
- Windows Server 2003 Service Pack 1
- Windows XP Professional x64 Edition (verfügbar für OEMs und Entwickler über MSDN)
- Windows Vista
- Windows 7
- Windows 8.0
- Windows 8.1
- Windows Server 2008 – 2016
Hinweis
Windows Server 2008 R2 oder höher ist nur als 64-Bit-Edition verfügbar. Windows 11 ist nur als 64-Bit- oder ARM64-Edition verfügbar.
- Unterschiede beim adressierbaren Arbeitsspeicher
- Angeben von "Große Adress"-fähig beim Erstellen
- Kompatibilität von 32-Bit-Anwendungen auf 64-Bit-Plattformen
- Portieren von Anwendungen auf 64-Bit-Plattformen
- Profilerstellung und Optimierung von portierten Anwendungen
- Verwalteter Code unter einem 64-Bit-Betriebssystem
- Auswirkungen auf die Leistung beim Ausführen eines 64-Bit-Betriebssystems
- Zusammenfassung
Unterschiede beim adressierbaren Arbeitsspeicher
Das erste, was die meisten Entwickler bemerken, ist, dass 64-Bit-Prozessoren einen großen Sprung in der Menge des physischen und virtuellen Speichers bieten, der adressiert werden kann.
32-Bit-Anwendungen auf 32-Bit-Plattformen können bis zu 2 GB adressieren.
32-Bit-Anwendungen, die mit dem Linkerflag /LARGEADDRESSAWARE:YES auf 32-Bit-Windows XP oder Windows Server 2003 mit der speziellen Startoption /3 gb erstellt wurden, können bis zu 3 GB adressieren. Dadurch wird der Kernel auf nur 1 GB beschränkt, was zu Fehlern bei einigen Treibern und/oder Diensten führen kann.
32-Bit-Anwendungen, die mit dem Linkerflag /LARGEADDRESSAWARE:YES in den 32-Bit-Editionen von Windows Vista, Windows Server 2008 und Windows 7 erstellt wurden, können Arbeitsspeicher bis zu der anzahl adressieren, die vom BCD-Element (Boot Configuration Data, Startkonfigurationsdaten) IncreaseUserVa angegeben wird. IncreaseUserVa kann einen Wert zwischen 2048 (Standard) und 3072 (entspricht der Menge des Arbeitsspeichers, der von der Startoption /3 gb unter Windows XP konfiguriert wurde) reicht. Der Rest von 4 GB wird dem Kernel zugeordnet und kann zu fehlerhaften Treiber- und Dienstkonfigurationen führen.
Weitere Informationen zu BCD finden Sie unter Startkonfigurationsdaten.
32-Bit-Anwendungen auf 64-Bit-Plattformen können bis zu 2 GB oder bis zu 4 GB mit dem Linkerflag /LARGEADDRESSAWARE:YES adressieren.
64-Bit-Anwendungen verwenden 43 Bits für die Adressierung, wodurch 8 TB virtuelle Adressen für Anwendungen und 8 TB für den Kernel reserviert sind.
Über den Arbeitsspeicher hinaus profitieren 64-Bit-Anwendungen, die speicherseitig zugeordnete Datei-E/A verwenden, stark vom erweiterten virtuellen Adressraum. Die 64-Bit-Architektur hat auch eine verbesserte Gleitkommaleistung und eine schnellere Übergabe von Parametern. Vierundsechzig-Bit-Prozessoren verfügen über die doppelte Anzahl von Registern, sowohl von universellen als auch von Streaming-SIMD-Erweiterungen (SSE) sowie von Unterstützung für SSE- und SSE2-Befehlssätze; viele 64-Bit-Prozessoren unterstützen sogar SSE3-Befehlssätze.
Angeben von "Große Adress"-fähig beim Erstellen
Es empfiehlt sich, beim Erstellen von 32-Bit-Anwendungen das Linkerflag /LARGEADDRESSAWARE anzugeben, auch wenn die Anwendung aufgrund der kostenlosen Vorteile nicht für eine 64-Bit-Plattform vorgesehen ist. Wie bereits erläutert, ermöglicht die Aktivierung dieses Flags für einen Build einem 32-Bit-Programm den Zugriff auf mehr Arbeitsspeicher mit speziellen Startoptionen auf einem 32-Bit-Betriebssystem oder einem 64-Bit-Betriebssystem. Entwickler müssen jedoch darauf achten, dass keine Zeigerannahmen getroffen werden, z. B. die Annahme, dass der High-Bit niemals in einem 32-Bit-Zeiger festgelegt ist. Im Allgemeinen ist das Aktivieren des Flags /LARGEADDRESSAWARE eine bewährte Methode.
Zweiunddreißig-Bit-Anwendungen, die große Adressen unterstützen, können zur Laufzeit ermitteln, wie viel gesamter virtueller Adressraum ihnen mit der aktuellen Betriebssystemkonfiguration zur Verfügung steht, indem Sie GlobalMemoryStatusEx aufrufen. Das ullTotalVirtual-Ergebnis reicht von 2147352576 Bytes (2 GB) bis 4294836224 Bytes (4 GB). Werte, die größer als 3221094400 (3 GB) sind, können nur in 64-Bit-Editionen von Windows abgerufen werden. Wenn IncreaseUserVa beispielsweise den Wert 2560 hat, lautet das Ergebnis ullTotalVirtual mit dem Wert 2684223488 Bytes.
Kompatibilität von 32-Bit-Anwendungen auf 64-Bit-Plattformen
Vierundsechzig-Bit-Windows-Betriebssysteme sind binärkompatibel mit der IA32-Architektur, und die meisten APIs, die 32-Bit-Anwendungen verwenden, sind über den Windows 32-Bit-Emulator unter Windows 64-Bit, WOW64, verfügbar. WOW64 hilft sicherzustellen, dass diese APIs wie gewünscht funktionieren.
WOW64 verfügt über eine Ausführungsebene, die das Marshalling von 32-Bit-Daten verarbeitet. WOW64 leitet DLL-Dateianforderungen um, leitet einige Registrierungsverzweigungen für 32-Bit-Anwendungen um und spiegelt einige Registrierungsverzweigungen für 32- und 64-Bit-Anwendungen wider.
Weitere Informationen zu WOW64 finden Sie unter WOW64-Implementierungsdetails.
Potenzielle Fehler bei der Kompatibilität
Die meisten Anwendungen, die für eine 32-Bit-Plattform entwickelt wurden, können problemlos auf einer 64-Bit-Plattform ausgeführt werden. Einige Anwendungen können Probleme haben, z. B. Folgendes:
- Alle Treiber für 64-Bit-Editionen von Windows-Betriebssystemen müssen 64-Bit-Versionen sein. Die Anforderung neuer 64-Bit-Treiber hat Auswirkungen auf Kopierschutzschemas, die auf alten Treibern basieren. Beachten Sie, dass Kernelmodustreiber authenticode-signiert sein müssen, um von 64-Bit-Editionen von Windows geladen zu werden.
- 64-Bit-Prozesse können keine 32-Bit-DLLs laden, und 32-Bit-Prozesse können keine 64-Bit-DLLs laden. Entwickler müssen sicherstellen, dass 64-Bit-Versionen von Drittanbieter-DLLs verfügbar sind, bevor sie mit der Entwicklung fortfahren. Wenn Sie eine 32-Bit-DLL in einem 64-Bit-Prozess verwenden müssen, kann die Prozessübergreifende Kommunikation (Inter-Process Communication, IPC) von Windows verwendet werden. COM-Komponenten können auch Out-of-Process-Server und Marshalling für die Kommunikation zwischen Grenzen nutzen, was jedoch zu Leistungseinbußen führen kann.
- Viele x64-Prozessoren sind auch Multikernprozessoren, und Entwickler müssen testen, wie sich dies auf ihre Legacyanwendungen auswirkt. Weitere Informationen zu Multikernprozessoren und den Auswirkungen auf Spieleanwendungen finden Sie unter Game Timing und Multicore-Prozessoren.
- Anwendungen sollten auch SHGetFolderPath aufrufen, um Dateipfade zu ermitteln, da sich einige Ordnernamen in bestimmten Fällen geändert haben. Beispielsweise würde CSIDL_PROGRAM_FILES "C:\Programme(x86)" für eine 32-Bit-Anwendung zurückgeben, die auf einer 64-Bit-Plattform statt "C:\Programme" ausgeführt wird. Entwickler müssen darauf achten, wie die Umleitungs- und Reflektionsfunktionen des WOW64-Emulators funktionieren.
Darüber hinaus müssen Entwickler vorsichtig sein, wenn sie 16-Bit-Programme verwenden, die sie möglicherweise noch verwenden. WOW64 kann keine 16-Bit-Anwendungen verarbeiten. dazu gehören alte Installationsprogramme und alle MS-DOS-Programme.
Hinweis
Die häufigsten Kompatibilitätsprobleme sind Installationsprogramme, die 16-Bit-Code ausführen und keine 64-Bit-Treiber für Kopierschutzschemas haben.
Im nächsten Abschnitt werden Probleme im Zusammenhang mit der Portierung von Code zu 64-Bit-Nativen für Entwickler erläutert, die sicherstellen möchten, dass ihre Legacyprogramme auf 64-Bit-Plattformen funktionieren. Es ist auch für Entwickler gedacht, die mit der 64-Bit-Programmierung nicht vertraut sind.
Portieren von Anwendungen auf 64-Bit-Plattformen
Die richtigen Tools und Bibliotheken erleichtern den Übergang von der 32-Bit- zur 64-Bit-Entwicklung. Das DirectX 9 SDK verfügt über Bibliotheken zur Unterstützung von x86- und x64-basierten Projekten. Microsoft Visual Studio 2005 und Visual Studio 2008 unterstützen die Codegenerierung für x86 und x64 und enthalten Bibliotheken, die für die Generierung von x64-Code optimiert sind. Es wird jedoch auch für Entwickler erforderlich sein, die Visual C-Runtimes mit ihren Anwendungen zu verteilen. Beachten Sie, dass die Express-Editionen von Visual Studio 2005 und Visual Studio 2008 nicht den x64-Compiler enthalten, aber die Editionen Standard, Professional und Team System.
Entwickler, die 32-Bit-Plattformen als Ziel haben, können sich auf die 64-Bit-Entwicklung vorbereiten, um den Übergang später zu vereinfachen. Beim Kompilieren von 32-Bit-Projekten sollten Entwickler das Flag /Wp64 verwenden, wodurch Warnungen zu Problemen generiert werden, die sich auf die Portabilität auswirken. Der Wechsel zu 64-Bit-Tools und -Bibliotheken wird anfangs wahrscheinlich viele neue Buildfehler verursachen. Daher ist es ratsam, bitneutrale Tools und Bibliotheken zu wechseln und alle Warnungen zu korrigieren, bevor Sie zu einem 64-Bit-Build wechseln.
Das Ändern von Tools, das Ändern von Bibliotheken und die Verwendung bestimmter Compilerflags reicht jedoch nicht aus. Annahmen in Codierungsstandards müssen neu ausgewertet werden, um sicherzustellen, dass aktuelle Codierungsstandards keine Portabilitätsprobleme zulassen. Portabilitätsprobleme können das Abschneiden von Zeigern, die Größe und Ausrichtung von Datentypen, die Abhängigkeit von 32-Bit-DLLs, die Verwendung von Legacy-APIs, Assemblycode und alte Binärdateien umfassen.
Hinweis
Visual C++ 2010 oder höher enthält die Header stdint.h und cstdint C99, die die Standardportabilitätstypen int32_t, uint32_t, int64_t, uint64_t, intptr_t und uintptr_t definieren. Die Verwendung dieser Datentypen zusammen mit den Standarddatentypen ptrdiff_t und size_t ist möglicherweise den windows-portabilty-Typen vorzuziehen, die unten zur Verbesserung der Portabilität von Code verwendet werden.
Zu den wichtigsten Problemen bei der Portierung gehören die folgenden:
-
Zeigerabkürzung
-
Zeiger sind 64-Bits auf einem 64-Bit-Betriebssystem, sodass das Umwandeln von Zeigern auf andere Datentypen zu abschneiden kann, und die Zeigerarithmetik zu Beschädigungen führen kann. Die Verwendung des Flags /Wp64 gibt in der Regel eine Warnung zu dieser Art von Problem aus, aber die Verwendung polymorpher Typen (INT_PTR, DWORD_PTR, SIZE_T, UINT_PTR usw.), wenn das Umwandeln von Zeigertypen eine bewährte Methode ist, um dieses Problem vollständig zu vermeiden. Da Zeiger auf neuen Plattformen 64-Bit sind, sollten Entwickler die Reihenfolge der Zeiger und die Datentypen in Klassen und Strukturen überprüfen, um den Abstand zu verringern oder zu beseitigen.
-
Datentypen und Binärdateien
-
Während Zeiger auf einer 64-Bit-Plattform von 32 Bit auf 64-Bit steigen, ist dies bei anderen Datentypen nicht der Fall. Datentypen mit fester Genauigkeit (DWORD32, DWORD64, INT32, INT64, LONG32, LONG64, UINT32, UINT64) können an Stellen verwendet werden, an denen die Größe des Datentyps bekannt sein muss; z. B. in einer Binärdateistruktur. Die Änderungen in der Zeigergröße und Datenausrichtung erfordern eine spezielle Behandlung, um die Kompatibilität zwischen 32 Bit und 64 Bit sicherzustellen. Weitere Informationen finden Sie unter Neue Datentypen.
-
Ältere Win32-APIs und Datenausrichtung
-
Einige Win32-APIs wurden veraltet und durch neutralere API-Aufrufe wie SetWindowLongPtr anstelle von SetWindowLongLong ersetzt.
Die Leistungseinbuße für nicht ausgerichtete Zugriffe ist auf der x64-Plattform größer als auf einer x86-Plattform. Die Makros TYPE_ALIGNMENT(t) und FIELD_OFFSET(t, Member) können verwendet werden, um Ausrichtungsinformationen zu bestimmen, die direkt vom Code verwendet werden können. Die richtige Verwendung dieser oben genannten Makros sollte potenzielle nicht ausgerichtete Zugriffsstrafen beseitigen.
Weitere Informationen zum Makro TYPE_ALIGNMENT, zum Makro FIELD_OFFSET und allgemeine 64-Bit-Programmierinformationen finden Sie unter 64-Bit-Windows-Programmierung: Migrationstipps: Zusätzliche Überlegungen und Regeln für die Verwendung von Zeigern.
-
Assemblycode
-
Inlineassemblycode wird auf 64-Bit-Plattformen nicht unterstützt und muss ersetzt werden. Änderungen in der Architektur haben sich möglicherweise zu Anwendungsengpässen geändert, und C/C++ oder systeminterne Komponenten können ähnliche Ergebnisse mit einfacher zu lesenem Code erzielen. Am besten empfiehlt es sich, den gesamten Assemblycode auf C oder C++ umzustellen. Systeminterne Funktionen können anstelle von Assemblycode verwendet werden, sollten aber erst verwendet werden, nachdem die vollständige Profilerstellung und Analyse durchgeführt wurde.
Die x87, MMX und 3DNow! Befehlssätze sind in 64-Bit-Modi veraltet. Die Anweisungen sind weiterhin vorhanden, um die Abwärtskompatibilität für den 32-Bit-Modus zu gewährleisten. Um Kompatibilitätsprobleme in Zukunft zu vermeiden, wird jedoch von derEn Verwendung in aktuellen und zukünftigen Projekten abgeraten.
-
Veraltete APIs
-
Einige ältere DirectX-APIs wurden für native 64-Bit-Anwendungen gelöscht: DirectPlay 4 und früher, DirectDraw 6 und früher, Direct3D 8 und früher sowie DirectInput 7 und früher. Außerdem ist die Kern-API von DirectMusic für native 64-Bit-Anwendungen verfügbar, aber die Leistungsebene und DirectMusic Producer sind veraltet.
Visual Studio stellt Veraltetkeitswarnungen aus, und diese Änderungen sind kein Problem für Entwickler, die die neuesten APIs verwenden.
Profilerstellung und Optimierung von portierten Anwendungen
Alle Entwickler müssen alle Anwendungen neu profilieren, die in neue Architekturen portiert werden. Viele Anwendungen, die auf 64-Bit-Plattformen portiert werden, weisen andere Leistungsprofile als ihre 32-Bit-Versionen auf. Entwickler müssen 64-Bit-Leistungstests ausführen, bevor sie bewerten, was optimiert werden muss. Die gute Nachricht ist, dass viele herkömmliche Optimierungen auf 64-Bit-Plattformen funktionieren. Darüber hinaus können 64-Bit-Compiler auch viele Optimierungen mit der richtigen Verwendung von Compilerflags und Codierungshinweisen durchführen.
Bei einigen Strukturen können ihre internen Datentypen neu sortiert werden, um Speicherplatz zu sparen und die Zwischenspeicherung zu verbessern. Arrayindizes können in einigen Fällen anstelle eines vollständigen 64-Bit-Zeigers verwendet werden. Das Flag /fp:fast kann die Gleitkommaoptimierung und Vektorisierung verbessern. Die Verwendung von __restrict, declspec(restrict) und declspec(noalias) kann dem Compiler helfen, Aliasing aufzulösen und die Verwendung der Registerdatei zu verbessern.
Weitere Informationen zu /fp:fast finden Sie unter /fp (Angeben Floating-Point Verhalten).
Weitere Informationen zu __restrict finden Sie unter Microsoft-Spezifische Modifizierer.
Weitere Informationen zu declspec(restrict) finden Sie unter Bewährte Methoden zur Optimierung.
Weitere Informationen zu declspec(noalias) finden Sie unter __declspec(noalias).
Verwalteter Code unter einem 64-Bit-Betriebssystem
Verwalteter Code wird von vielen Spieleentwicklern in ihrer Toolkette verwendet, sodass ein Verständnis dessen, wie er sich auf einem 64-Bit-Betriebssystem verhält, hilfreich sein kann. Verwalteter Code ist befehlsneutral. Wenn Sie also eine verwaltete Anwendung auf einem 64-Bit-Betriebssystem ausführen, kann die Common Language Runtime (CLR) sie entweder als 32-Bit- oder 64-Bit-Prozess ausführen. Standardmäßig führt die CLR verwaltete Anwendungen als 64-Bit aus, und sie sollten problemlos funktionieren. Wenn Ihre Anwendung jedoch von einer DLL abhängig ist, die systemeigene 32-Bit-Datei ist, schlägt Ihre Anwendung fehl, wenn sie versucht, diese DLL aufzurufen. Ein 64-Bit-Prozess benötigt vollständigen 64-Bit-Code, und eine 32-Bit-DLL kann nicht aus einem 64-Bit-Prozess aufgerufen werden. Die beste langfristige Lösung besteht darin, Ihren nativen Code auch als 64-Bit zu kompilieren, aber eine absolut sinnvolle kurzfristige Lösung besteht darin, Ihre verwaltete Anwendung einfach nur als x86 zu markieren, indem Sie das Buildflag /platform:x86 verwenden.
Leistungsauswirkungen der Ausführung eines 64-Bit-Betriebssystems
Da Prozessoren mit AMD64- und Intel 64-Architektur 32-Bit-Anweisungen nativ ausführen können, können sie 32-Bit-Anwendungen mit voller Geschwindigkeit ausführen, auch unter einem 64-Bit-Betriebssystem. Beim Aufrufen von Betriebssystemfunktionen fallen bescheidene Kosten für die Konvertierung von Parametern zwischen 32-Bit und 64-Bit an, aber diese Kosten sind im Allgemeinen vernachlässigbar. Dies bedeutet, dass beim Ausführen von 32-Bit-Anwendungen auf einem 64-Bit-Betriebssystem keine Verlangsamung angezeigt werden sollte.
Wenn Sie Anwendungen als 64-Bit kompilieren, werden die Berechnungen komplizierter. Ein 64-Bit-Programm verwendet 64-Bit-Zeiger, und seine Anweisungen sind etwas größer, sodass der Arbeitsspeicherbedarf leicht erhöht wird. Dies kann zu einem leichten Leistungsabfall führen. Auf der anderen Seite werden doppelt so viele Register und die Möglichkeit, 64-Bit-ganzzahlige Berechnungen in einer einzigen Anweisung durchzuführen, oft mehr als kompensiert. Das Nettoergebnis ist, dass eine 64-Bit-Anwendung möglicherweise etwas langsamer ausgeführt wird als dieselbe Anwendung, die als 32-Bit kompiliert wurde, aber oft etwas schneller ausgeführt wird.
Zusammenfassung
Vierundsechzig-Bit-Architekturen ermöglichen Es Entwicklern, die Einschränkungen hinsichtlich des Aussehens, des Klangs und der Wiedergabe von Spielen zu verschieben. Der Übergang von der 32-Bit-Programmierung zur 64-Bit-Programmierung ist jedoch nicht trivial. Wenn Sie die Unterschiede zwischen den beiden kennen und die neuesten Tools verwenden, kann der Übergang zu 64-Bit-Plattformen einfacher und schneller sein.
Weitere Informationen zur 64-Bit-Programmierung finden Sie im Visual C++-Developer Center: 64-Bit-Programmierung.