Nel sistema Android, la soglia del limite di memoria per Memory Limiter (Android 17+) e il valore di riferimento per la metrica relativa alla memoria in Google Play Console è 'RSS anonimo + swap'. Questo valore rappresenta il livello di pressione della memoria fisica effettivamente occupato dal processo ed è una metrica fondamentale da monitorare per il funzionamento stabile dell'app.
Al momento, è difficile misurare la memoria utilizzata che corrisponda esattamente a "RSS anonimo + swap" sia in fase di runtime sia staticamente all'interno di Unity Engine.
Per risolvere questo problema, questa pagina spiega come monitorare il valore "RSS anonimo + swap" con elevata affidabilità tramite approssimazione utilizzando Unity Profiler, l'API ProfileRecorder e Unity Memory Profiler in un ambiente Unity Engine.
Controllare la memoria utilizzata in fase di runtime
In Unity, misurare direttamente l'utilizzo esatto della memoria "RSS anonimo + swap" di Android in fase di runtime senza overhead può essere difficile. Tuttavia, puoi stimare con precisione questo valore (con una varianza di circa il 10%) utilizzando le API Profiler integrate di Unity.
Metodo 1: utilizzare Profiler
Puoi stimare la memoria utilizzata totale sommando i valori restituiti dalle seguenti API Profiler:
using UnityEngine;
using UnityEngine.Profiling;
public class MemoryMonitor : MonoBehaviour
{
public long GetEstimatedMemoryUsageBytes()
{
long totalReserved = Profiler.GetTotalReservedMemoryLong();
long monoHeapSize = Profiler.GetMonoHeapSizeLong();
return totalReserved + monoHeapSize;
}
}
Metodo 2: utilizzare la classe ProfilerRecorder
Puoi monitorare le metriche Memoria riservata totale e Memoria riservata Gfx utilizzando ProfilerRecorder:
Nelle build di sviluppo: calcola 'Memoria riservata totale' - 'Memoria riservata Gfx'.
Nelle build di release: utilizza direttamente 'Memoria riservata totale'.
using Unity.Profiling;
using UnityEngine;
public class MemoryMonitor : MonoBehaviour
{
ProfilerRecorder totalRecorder;
#if DEVELOPMENT_BUILD
ProfilerRecorder gfxRecorder;
#endif
private void OnEnable()
{
totalRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Total Reserved Memory");
#if DEVELOPMENT_BUILD
gfxRecorder = ProfilerRecorder.StartNew(ProfilerCategory.Memory, "Gfx Reserved Memory");
#endif
}
private void OnDisable()
{
totalRecorder.Dispose();
#if DEVELOPMENT_BUILD
gfxRecorder.Dispose();
#endif
}
public long GetEstimatedMemoryUsageBytes()
{
#if DEVELOPMENT_BUILD
if (totalRecorder.Valid && gfxRecorder.Valid)
{
return totalRecorder.LastValue - gfxRecorder.LastValue;
}
#else
if (totalRecorder.Valid)
{
return totalRecorder.LastValue;
}
#endif
return 0;
}
}
Limitazione:
Le allocazioni di memoria che ignorano Memory Manager di Unity (ad es. NativeMalloc(IntPtr size)) non possono essere monitorate da queste API.
Queste API potrebbero non essere supportate a seconda della versione di Unity.
Analizzare la suddivisione della memoria (analisi statica)
Se viene rilevato un utilizzo elevato della memoria utilizzata in fase di runtime, devi identificare dove viene consumata la memoria. L'analisi della distribuzione della memoria consente di eliminare le allocazioni non necessarie e ridurre il footprint della memoria complessivo del gioco.
Unity Memory Profiler
Per eseguire un'analisi approfondita della memoria e ottimizzare il gioco, utilizza il pacchetto Unity Memory Profiler. Per individuare gli elementi corrispondenti all'utilizzo 'RSS anonimo + swap' del sistema operativo Android:
- Acquisisci uno snapshot utilizzando Unity Memory Profiler.
- Apri lo snapshot e vai a Tutta la memoria > Memoria residente sul dispositivo.
Calcola la somma dei seguenti elementi:
- Untracked
- Android Runtime
- Nativo
- Gestito
Figura 1. Le descrizioni della memoria sono memorizzate nella memoria residente
La somma totale funge da sostituto pratico per "RSS anonimo + swap" del sistema operativo Android, fornendo informazioni utili per l'analisi della memoria del gioco.
Limitazione:
In caso di forte pressione della memoria, il sistema operativo Android potrebbe comprimere o scambiare le pagine di memoria attive per liberare RAM. Poiché Unity Memory Profiler non può monitorare la memoria scambiata, potrebbero verificarsi discrepanze durante gli scenari di utilizzo elevato della memoria utilizzata.
Queste funzionalità potrebbero essere limitate a seconda della versione di Unity.
Esempi di script C#
Puoi fare riferimento agli script AndroidAndroidProcessStats.cs e
GameMemoryMonitor.cs per esempi su come monitorare lo stato e
le impronte di memoria dei processi del gioco in fase di runtime.
- Lo script
AndroidProcessStatsmostra come utilizzare JNI (Java Native Interface) per collegarsi alle APIActivityManagerdi Android e fornisce funzionalità per recuperare i processi in esecuzione, la loro importanza e lo stato a livello di sistema operativo. Contiene anche metodi leggeri per leggere le statistiche sulla memoria direttamente dal file system/procdi Linux. - Lo script
GameMemoryMonitormostra come collegare queste informazioni per il monitoraggio e il debug continui, incluso come eseguire il polling delle API Android su un thread in background per evitare l'overhead delle prestazioni (poiché l'utilizzo di JNI e il polling per le informazioni sulla memoria possono essere costosi) e come collegarsi agli eventi del ciclo di vita comeOnApplicationPauseper monitorare le modifiche alla memoria quando l'app viene messa in background o ripresa.
Per utilizzare questi strumenti, aggiungi entrambi gli script alla cartella Assets e collega lo script GameMemoryMonitor a un GameObject nella scena.
Valutazione più accurata
Per verificare i valori esatti di 'RSS anonimo + swap' del sistema operativo Android, utilizza Perfetto. Ti consente di misurare la memoria utilizzata precisa a livello di sistema e di analizzare a fondo il footprint della memoria del gioco.