Die Unreal Engine (UE) verwendet einen Mark-and-Sweep Garbage Collector, um den UObject-Speicher zu verwalten. Bei Soft-Echtzeit-Anwendungen hatten Garbage Collector bisher einen großen Nachteil: das Potenzial, Gameplay-Ruckler zu erzeugen, während der Garbage Collector bestimmt, welcher Objektspeicher zurückgefordert werden kann. In der UE wird dieser Prozess Erreichbarkeitsanalyse genannt. UE ist darauf angewiesen, dass diese Phase der Garbage Collection innerhalb eines einzigen Frames abgeschlossen wird, wodurch die gesamte UObject-Verarbeitung (insbesondere das Gameplay) kurzzeitig angehalten wird. Je mehr Objekte von der Erreichbarkeitsanalyse gescannt werden, desto länger wird die Pause, was zu sichtbaren Gameplay-Rucklern führen kann. Es gibt verschiedene Möglichkeiten, wie Programmierer Hitches vermeiden können, z. B.:
Knappe UObject-Budgets einhalten.
Nutzung von UObject-Pools.
Garbage Collection bei normalem Gameplay deaktivieren.
Diese Workarounds erhöhen jedoch meist die Codekomplexität und die Gesamtkosten des Projekts.
Inkrementelle Erreichbarkeitsanalyse
UE verbessert dies durch Verwendung der inkrementellen Erreichbarkeitsanalyse. Nutzer haben nun die Fähigkeit, die Phase der Erreichbarkeitsanalyse des Garbage Collectors über mehrere Frames mit einem konfigurierbaren, weichen Zeitlimit pro Frame aufzuteilen. Die Engine trackt UObject Referenzen zwischen Erreichbarkeitsiterationen mittels TObjectPtr-Eigenschaften. Das bedeutet, dass jede Zuweisung eines TObjectPtr-freigegebenen UPROPERTY das Objekt sofort als erreichbar markiert, während die Garbage Collection läuft. Dies wird auch als Garbage Collector -Schreib-Barriere bezeichnet.
Die Engine hat bereits darauf umgestellt, TObjectPtr anstelle von rohen C++-Pointern an allen Stellen zu verwenden, die UObjects dem Garbage Collector exponieren, einschließlich aller UObject- und FGCObject AddReferencedObjects-Funktionen. Für den Einsatz der inkrementellen Erreichbarkeitsanalyse in Projekten, die mit der Unreal Engine gebaut wurden, ist es unerlässlich, alle UPROPERTY-Instanzen so zu konvertieren, dass sie TObjectPtr anstelle von rohem C++ verwenden, da die Garbage Collection sonst einen Teil des Speichers von UObjects zu früh zurückfordern könnte. Wir veröffentlichen diese Funktion zunächst als experimentelle Funktion, da es weiterhin möglich ist, dass die Erreichbarkeitsanalysephase das festgelegte Zeitlimit überschreitet.
Inkrementelle Erreichbarkeitsanalyse aktivieren
Die inkrementelle Erreichbarkeitsanalyse kann mit den folgenden Konsolenvariablen aktiviert werden, wenn Sie sie zur DefaultEngine.ini Ihres Projekts hinzufügen:
[ConsoleVariables]
gc.AllowIncrementalReachability=1 ; enables Incremental Reachability Analysis
gc.AllowIncrementalGather=1 ; enables Incremental Gather Unreachable Objects
gc.IncrementalReachabilityTimeLimit=0.002 ; sets the soft time limit to 2msZusätzliche Konsolenvariablen
Sie können auch Konsolenvariablen für Belastungstests und Debugging-Zwecke verwenden:
| Konsolenvariable | Beschreibung | Typ |
|---|---|---|
| Delay die Erreichbarkeitsanalyse um die angegebene Anzahl von Frames. Wird für den Stresstest der GC-Barriere verwendet. |
|
| Führen Sie einen Test aus, nachdem die Erreichbarkeitsanalyse abgeschlossen wurde, um sicherzustellen, dass kein erreichbares (gültiges) Objekt auf ein unerreichbares (bald zerstörtes) Objekt verweist. | 0: deaktiviert, 1: aktiviert |
| Die inkrementelle Garbage Collection immer neu starten, nachdem die vorherige abgeschlossen ist. | 0: deaktiviert, 1: aktiviert |
Performance-Vergleich
Unten sehen Sie eine Unreal Insights-Visualisierung des Performance Diagramms eines Sample-Projekts mit deaktivierter inkrementeller Erreichbarkeit. Die blaue Linie stellt die Gesamt Zeit Frame und die orangefarbene Linie die Zeit, die Erreichbarkeitsanalyse benötigt hat. Unreal Insights zeichnet eine kontinuierliche Diagramm zwischen einzelnen Events, die durch mehrere Frames getrennt sind; Auch wenn es so wirken mag, als würde Garbage Collection über die gesamte Zeitleiste laufen, läuft sie nur für einen Frame gleichzeitig.
Im ersten Bild des folgenden Diagramms sehen Sie bei jedem Durchlauf der Garbage Collection einen Spitzenwert (erkennbar an den GC-Beschriftungen oben auf der Zeitleiste).
Im zweiten Bild sehen Sie bei aktivierter inkrementeller Erreichbarkeit, dass die GC Lag-Spuren weg sind und die inkrementelle Erreichbarkeit nun auf mehrere Frames aufgeteilt wird (repräsentiert durch die nun breiteren leicht Balken).
Bekannte Einschränkungen
Inkrementelle Erreichbarkeit ist nicht vollständig Thread-sicher. Unter bestimmten Umständen wird ein Objekt, das in einem Arbeiter-Thread manipuliert wird, nicht als erreichbar markiert, während der Garbage Collector das UObject-Diagramm scannt. Das kann dazu führen, dass das Objekt vorzeitig von der Garbage Collection beseitigt wird. Wir empfehlen, die schrittweise Erreichbarkeit nur in Single-Thread-Builds zu aktivieren (Beispiel: auf reservierten Servern).