La memoria utilizzata è fondamentale nello sviluppo di giochi per Android. Quando sviluppi giochi utilizzando Unreal Engine, devi continuamente analizzare e monitorare lo stato della memoria per soddisfare questi vincoli, prevenendo perdite di memoria e allocazioni eccessive.
Risparmio di memoria grazie alla riduzione della permutazione degli shader
Rimuovendo le opzioni inutilizzate in Lighting o Mobile Shader Permutation
Reduction, puoi ridurre al minimo il numero di permutazioni degli shader. In questo modo, riduci notevolmente le dimensioni del pacchetto dell'app, il numero di oggetti di stato della pipeline (PSO) e impedisci la creazione di target di rendering o texture fittizie inutilizzati, con conseguente riduzione della memoria di runtime e miglioramento delle prestazioni.
Per ulteriori informazioni, consulta la sezione Misc Lighting and Shader Permutation Reduction Settings for Mobile in Performance Guidelines for Mobile Devices.
Ottimizzazione del caricamento degli asset
Quando carichi gli asset utilizzando riferimenti hard, i contenuti collegati che non vengono nemmeno utilizzati nel gioco vengono caricati contemporaneamente in memoria, causando un consumo di memoria non necessario. In particolare, quando l'ereditarietà viene utilizzata in modo errato in Blueprints, vengono allocati CDO (Class Default Objects) non necessari dai genitori, sprecando una quantità significativa di memoria. In questi casi, applica le seguenti tecniche per ottimizzare la memoria utilizzata.
- Definizione del codice C++ e separazione dei dati: definisci le funzionalità principali
utilizzando
UCLASS(Abstract)nel codice C++, separandole dai dati effettivi. - Riduci al minimo l'ereditarietà: esegui la configurazione dei dati e il caricamento degli asset solo in Blueprints dei nodi foglia.
- Utilizza riferimenti indiretti: applica riferimenti di proprietà indiretti utilizzando
TSoftObjectPtrper evitare riferimenti hard e carica gli asset solo quando necessario in fase di runtime. - Precauzioni: quando utilizzi il caricamento asincrono degli asset, assicurati che i controlli di validità
(
IsValid) vengano eseguiti durante il callback di completamento del caricamento per evitare puntatori sospesi o arresti anomali.
Per ulteriori informazioni, consulta la sezione Referencing Assets e Building Mobile Games with UE5 (Fare riferimento agli asset e creare giochi per dispositivi mobili con UE5).
Ottimizzazione dei puntatori intelligenti e della garbage collection (GC)
L'utilizzo di puntatori intelligenti (come TSharedPtr e TWeakPtr) durante lo sviluppo in C++ impedisce puntatori sospesi e perdite di memoria. Inoltre, l'utilizzo di TWeakPtr evita la creazione di riferimenti hard agli oggetti, in modo che il garbage collector non incrementi i conteggi dei riferimenti durante la raccolta degli oggetti. In questo modo, si evita la sopravvivenza non necessaria degli oggetti e si riduce la complessità del grafico di riferimento che GC deve attraversare, riducendo significativamente l'overhead di GC. La garbage collection può essere gestita in modo efficace negli ambienti mobile attivando ForceGarbageCollection durante le transizioni di livello o i periodi di inattività, ad esempio quando non è presente alcuna interazione dell'utente. Inoltre, può essere attivata quando il gioco è in uno stato percepibile o in background (ad esempio, callback onStop), assicurando che la garbage collection venga eseguita senza influire sull'esperienza di gioco attiva.
Per ulteriori informazioni, consulta la sezione Garbage Collection (Garbage collection) e Smart Pointer (puntatore intelligente).
Ottimizzazione tramite la compressione della tabella di rilocazione
La compressione della tabella di rilocazione è un metodo di ottimizzazione che comprime le dimensioni della tabella di rilocazione nei file binari ELF per ridurre le dimensioni dei file binari Android. Quando Android minSDKVersion è 23 o superiore, è supportata la compressione della tabella di rilocazione APS; quando minSDKVersion è 28 o superiore, è supportata anche la compressione della tabella di rilocazione RELR, che riduce significativamente le dimensioni del file .so. In questo modo, non solo si riducono le dimensioni del download, ma anche il footprint della memoria del file .so mmap in fase di runtime, mitigando la pressione complessiva della memoria fisica.
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";
}
Per applicare questa ottimizzazione, verifica che l'opzione Enable compression of relocation tables (Attiva la compressione delle tabelle di rilocazione) in Project Settings (Impostazioni progetto) o la variabile bEnableAdvancedBinaryCompression sia attivata.
Per verificare se la compressione RELR è applicata correttamente al file binario, utilizza lo strumento llvm-readelf di Android NDK.
llvm-readelf -d libUnreal.so | grep RELR
In pratica, la creazione del modello ThirdPerson di Unreal Engine e la misurazione tramite dumpsys meminfo confermano una riduzione dell'utilizzo di PSS e RSS per .so mmap.
| Categoria | PSS totale | Private Dirty | Private Clean | Swap Dirty | RSS totale |
|---|---|---|---|---|---|
| .so mmap Prima della compressione | 170.210 | 24.360 | 141.564 | 0 | 242.204 |
| .so mmap Dopo la compressione | 138.031 | 24.748 | 108.976 | 0 | 210.140 |
Compressione delle texture
Utilizza la compressione delle texture appropriata per ridurre il footprint della memoria delle risorse grafiche complessive. L'utilizzo di Adaptive Scalable Texture Compression (ASTC), lo standard mobile, offre una qualità visiva superiore rispetto a ETC2 con le stesse dimensioni o raggiunge rapporti di compressione più elevati con un consumo di memoria inferiore con lo stesso target di qualità visiva.
Ottimizzazione dello streaming delle texture
Negli ambienti mobile, l'utilizzo diretto delle dimensioni del pool di texture streaming predefinite di Unreal Engine può preallocare un pool di memoria eccessivamente grande rispetto alle specifiche del dispositivo. Pertanto, è ideale definire i profili dei dispositivi mobile e selezionare le dimensioni del pool di streaming delle texture appropriate in base ai limiti di memoria del dispositivo. Inoltre, utilizza la funzionalità Statistic (Statistiche) dell'Editor per controllare le statistiche delle texture e identificare le texture che consumano molta memoria e che occupano risoluzioni estreme in fase di runtime. Combina questa funzionalità con la funzionalità Required Texture Resolution (Risoluzione texture richiesta) per applicare limiti o ridurre le risoluzioni massime delle texture più impegnative, mantenendo l'utilizzo delle risorse controllato all'interno del buffer di memoria delle texture allocato.