Die Arbeitsspeichernutzung ist bei der Entwicklung von Android-Spielen von entscheidender Bedeutung. Wenn Sie Spiele mit der Unreal Engine entwickeln, müssen Sie den Speicherstatus kontinuierlich analysieren und verfolgen, um diese Speicherbeschränkungen zu erfüllen und Speicherlecks und übermäßige Speicherzuweisungen zu vermeiden.
Speichereinsparungen durch Reduzierung der Shader-Permutationen
Wenn Sie nicht verwendete Optionen in Lighting oder Mobile Shader Permutation
Reduction entfernen, können Sie die Anzahl der Shader-Permutationen minimieren. Dadurch wird die Größe des App-Pakets erheblich reduziert, die Anzahl der Pipeline-Statusobjekte (Pipeline State Objects, PSOs) verringert und die Erstellung nicht verwendeter Renderziele oder Dummy-Texturen verhindert. Das führt zu einer geringeren Arbeitsspeichernutzung zur Laufzeit und einer besseren Leistung.
Weitere Informationen finden Sie im Abschnitt Misc Lighting and Shader Permutation Reduction Settings for Mobile in den Leistungsrichtlinien für Mobilgeräte.
Optimierung des Asset-Ladens
Wenn Assets mit festen Referenzen geladen werden, werden gleichzeitig verbundene Inhalte, die im Spiel gar nicht verwendet werden, in den Arbeitsspeicher geladen. Das führt zu einer unnötigen Speichernutzung. Insbesondere wenn die Vererbung in Blueprints missbraucht wird, werden unnötige CDOs (Class Default Objects) von übergeordneten Elementen zugewiesen, wodurch eine erhebliche Menge an Arbeitsspeicher verschwendet wird. In solchen Fällen können Sie die folgenden Techniken anwenden, um die Arbeitsspeichernutzung zu optimieren.
- C++-Code-Definition und Datentrennung: Definieren Sie Kernfunktionen
mit
UCLASS(Abstract)im C++-Code und trennen Sie sie von den eigentlichen Daten. - Vererbung minimieren: Führen Sie die Dateneinrichtung und das Asset-Laden nur in Blueprints für Blattknoten aus.
- Indirekte Referenzen verwenden: Wenden Sie indirekte Eigenschaftenreferenzen mit
TSoftObjectPtran, um feste Referenzen zu vermeiden, und laden Sie Assets asynchron nur dann, wenn sie zur Laufzeit benötigt werden. - Vorsichtsmaßnahmen: Wenn Sie das asynchrone Asset-Laden verwenden, achten Sie darauf, dass bei der Rückruffunktion für den Abschluss des Ladens Gültigkeitsprüfungen
(
IsValid) durchgeführt werden, um hängende Zeiger oder Abstürze zu vermeiden.
Weitere Informationen finden Sie unter Referenzieren von Assets und Erstellen von mobilen Spielen mit UE5.
Optimierung von Smart-Pointern und automatischer Speicherbereinigung (GC)
Wenn Sie bei der C++-Entwicklung Smart-Pointer wie TSharedPtr und TWeakPtr verwenden, können Sie hängende Zeiger und Speicherlecks vermeiden. Außerdem wird durch die Verwendung von TWeakPtr die Erstellung starker Referenzen auf Objekte vermieden, sodass der Garbage Collector die Referenzzähler beim Erfassen von Objekten nicht erhöht. Dadurch wird das unnötige Überleben von Objekten verhindert und die Komplexität des Referenzgraphen verringert, den der Garbage Collector durchlaufen muss. Das reduziert den GC-Overhead erheblich. Die Garbage Collection kann in mobilen Umgebungen effektiv verwaltet werden, indem ForceGarbageCollection bei Levelübergängen oder Inaktivitätsphasen ausgelöst wird, z. B. wenn keine Nutzerinteraktion stattfindet. Außerdem kann sie ausgelöst werden, wenn sich das Spiel in einem wahrnehmbaren Zustand befindet oder im Hintergrund ausgeführt wird (z. B. onStop-Rückrufe). So wird sichergestellt, dass die automatische Speicherbereinigung durchgeführt wird, ohne das aktive Gameplay zu beeinträchtigen.
Weitere Informationen finden Sie unter Garbage Collection und Smart-Pointer.
Optimierung durch Komprimierung der Umsiedlungstabelle
Die Komprimierung der Umsiedlungstabelle ist eine Optimierungsmethode, mit der die Größe der Umsiedlungstabelle in ELF-Binärdateien komprimiert wird, um die Größe von Android-Binärdateien zu reduzieren. Wenn die Android-Mindestversion des SDK 23 oder höher ist, wird die APS-Komprimierung der Umsiedlungstabelle unterstützt. Bei einer Mindestversion des SDK von 28 oder höher wird zusätzlich die RELR-Komprimierung der Umsiedlungstabelle unterstützt, wodurch die Größe der .so-Datei erheblich reduziert wird. Dadurch wird nicht nur die Downloadgröße verringert, sondern auch der Speicherbedarf der .so-mmap-Datei zur Laufzeit reduziert, wodurch der Gesamtdruck auf den physischen Arbeitsspeicher verringert wird.
AndroidToolChain.cs
if (MinSDKVersion >= 28)
{
Result += " -Wl,--pack-dyn-relocs=android+relr,--use-android-relr-tags";
}
else if (MinSDKVersion >= 23)
{
Result += " -Wl,--pack-dyn-relocs=android";
}
Wenn Sie diese Optimierung anwenden möchten, prüfen Sie, ob in den Projekteinstellungen Enable compression of relocation tables (Komprimierung von Umsiedlungstabellen aktivieren) oder die Variable bEnableAdvancedBinaryCompression aktiviert ist.
Mit dem Tool llvm-readelf aus dem Android NDK können Sie prüfen, ob die RELR-Komprimierung ordnungsgemäß auf die Binärdatei angewendet wurde.
llvm-readelf -d libUnreal.so | grep RELR
In der Praxis bestätigt das Erstellen der ThirdPerson-Vorlage von Unreal Engine und die Messung mit dumpsys meminfo eine Reduzierung der PSS- und RSS-Nutzung für die .so-mmap-Datei.
| Kategorie | PSS insgesamt | Private Dirty | Private Clean | Swap Dirty | RSS insgesamt |
|---|---|---|---|---|---|
| .so-mmap-Datei vor der Komprimierung | 170.210 | 24.360 | 141.564 | 0 | 242.204 |
| .so-mmap-Datei nach der Komprimierung | 138.031 | 24.748 | 108.976 | 0 | 210.140 |
Texturkomprimierung
Verwenden Sie eine geeignete Texturkomprimierung, um den Speicherbedarf der gesamten Grafikressourcen zu reduzieren. Mit der adaptiven skalierbaren Texturkomprimierung (Adaptive Scalable Texture Compression, ASTC), dem mobilen Standard, wird bei gleicher Größe eine höhere visuelle Qualität als mit ETC2 erzielt. Alternativ können bei gleichem Ziel für die visuelle Qualität höhere Komprimierungsraten mit geringerer Speichernutzung erreicht werden.