Come controllare la memoria utilizzata con gli strumenti Unity

Nel sistema Android, la soglia del limite di memoria per Memory Limiter (Android 17+) e il valore di riferimento per la metrica di memoria in Google Play Console è 'anonymous RSS + swap'. Questo valore rappresenta il livello di pressione della memoria fisica effettivamente occupata 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 "anonymous RSS + swap" sia in fase di tempo di esecuzione sia staticamente all'interno di Unity Engine.

Per risolvere questo problema, questa pagina spiega come monitorare il valore "anonymous RSS + 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 'anonymous RSS + 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 Total Reserved Memory e Gfx Reserved Memory utilizzando ProfilerRecorder:

  • Nelle build di sviluppo: calcola 'Total Reserved Memory' - 'Gfx Reserved Memory'.

  • Nelle build di release: utilizza direttamente "Total Reserved Memory".

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 di 'anonymous RSS + swap' del sistema operativo Android:

  1. Acquisisci uno snapshot utilizzando Unity Memory Profiler.
  2. Apri lo snapshot e vai a All of Memory > Resident Memory on Device.
  3. Calcola la somma dei seguenti elementi:

    • Untracked
    • Android Runtime
    • Native
    • Managed
    Metriche di memoria visualizzabili quando è impostata su Memoria residente in Unity Memory Profiler
    Figura 1. Le descrizioni della memoria sono memorizzate nella memoria residente

La somma totale funge da sostituto pratico per "anonymous RSS + 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.

Valutazione più accurata

Per verificare i valori esatti di 'anonymous RSS + 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.