Jak sprawdzić wykorzystanie pamięci za pomocą narzędzi Unity

W systemie Android próg limitu pamięci dla Memory Limiter (Android 17+) i wartość odniesienia dla danych o pamięci w Konsoli Google Play to 'anonimowy RSS + przestrzeń wymiany'. Ta wartość reprezentuje poziom obciążenia pamięci fizycznej faktycznie zajmowanej przez proces i jest kluczowym parametrem, który należy monitorować, aby zapewnić stabilne działanie aplikacji.

Obecnie trudno jest zmierzyć wykorzystanie pamięci, które dokładnie odpowiada „anonimowemu RSS + przestrzeni wymiany”, zarówno w czasie działania, jak i statycznie w silniku Unity.

Aby rozwiązać ten problem, na tej stronie opisujemy, jak śledzić wartość „anonimowy RSS + przestrzeń wymiany” z dużą niezawodnością za pomocą przybliżenia przy użyciu narzędzia Unity Profiler, interfejsu ProfileRecorder API i narzędzia Unity Memory Profiler w środowisku silnika Unity.

Sprawdzanie wykorzystania pamięci w czasie działania

W Unity bezpośrednie mierzenie dokładnego wykorzystania pamięci „anonimowy RSS + przestrzeń wymiany” w systemie Android w czasie działania bez obciążenia może być trudne. Możesz jednak dokładnie oszacować tę wartość (z odchyleniem około 10%) za pomocą wbudowanych interfejsów API narzędzia Unity Profiler.

Metoda 1: użycie Profilera

Możesz oszacować całkowite wykorzystanie pamięci, sumując wartości zwracane przez te interfejsy API narzędzia Profiler:

using UnityEngine;
using UnityEngine.Profiling;

public class MemoryMonitor : MonoBehaviour
{
    public long GetEstimatedMemoryUsageBytes()
    {
        long totalReserved = Profiler.GetTotalReservedMemoryLong();
        long monoHeapSize = Profiler.GetMonoHeapSizeLong();

        return totalReserved + monoHeapSize;
    }
}

Metoda 2: użycie klasy ProfilerRecorder

Za pomocą narzędzia ProfilerRecorder możesz śledzić dane Total Reserved Memory i Gfx Reserved Memory:

  • W kompilacjach deweloperskich: oblicz wartość „Total Reserved Memory” - „Gfx Reserved Memory”.

  • W kompilacjach produkcyjnych: użyj bezpośrednio wartości „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;
    }
}

Ograniczenie:

  • Alokacji pamięci, które omijają menedżera pamięci Unity (np. NativeMalloc(IntPtr size)), nie można śledzić za pomocą tych interfejsów API.

  • Te interfejsy API mogą nie być obsługiwane w zależności od wersji Unity.

Analizowanie podziału pamięci (analiza statyczna)

Jeśli w czasie działania wykryjesz wysokie wykorzystanie pamięci, musisz określić, gdzie jest ona zużywana. Analiza dystrybucji pamięci pozwala wyeliminować niepotrzebne alokacje i zmniejszyć ogólne wykorzystanie pamięci gry.

Unity Memory Profiler

Aby przeprowadzić szczegółową analizę pamięci i zoptymalizować grę, użyj pakietu Unity Memory Profiler. Aby znaleźć elementy odpowiadające wykorzystaniu „anonimowy RSS + przestrzeń wymiany” w systemie operacyjnym Android:

  1. Zrób migawkę za pomocą narzędzia Unity Memory Profiler.
  2. Otwórz migawkę i przejdź do sekcji All of Memory > Resident Memory on Device (Cała pamięć > Pamięć rezydentna na urządzeniu).
  3. Oblicz sumę tych elementów:

    • Untracked
    • środowisko wykonawcze Androida
    • Natywna
    • Zarządzane
    Wskaźniki pamięci widoczne po ustawieniu opcji Pamięć rezydentna w profilerze pamięci Unity
    Rysunek 1. Opisy pamięci są przechowywane w pamięci rezydentnej.

Suma całkowita stanowi praktyczny zamiennik „anonimowy RSS + przestrzeń wymiany” w systemie operacyjnym Android i dostarcza przydatnych informacji do analizy pamięci gry.

Ograniczenie:

  • Przy dużym obciążeniu pamięci system operacyjny Android może skompresować lub przenieść aktywne strony pamięci do przestrzeni wymiany, aby zwolnić pamięć RAM. Ponieważ narzędzie Unity Memory Profiler nie może śledzić pamięci przeniesionej do przestrzeni wymiany, w scenariuszach dużego wykorzystania pamięci mogą wystąpić rozbieżności.

  • Te funkcje mogą być ograniczone w zależności od wersji Unity.

Przykładowe skrypty w języku C#

Przykłady monitorowania stanu i rozmiaru pamięci procesów gry w czasie działania znajdziesz w skryptach AndroidAndroidProcessStats.cs i GameMemoryMonitor.cs.

  • Skrypt AndroidProcessStats pokazuje, jak używać JNI (Java Native Interface) do łączenia się z interfejsami API ActivityManager w systemie Android. Zawiera też funkcje do pobierania uruchomionych procesów, ich ważności i stanu na poziomie systemu operacyjnego. Zawiera też proste metody odczytywania statystyk pamięci bezpośrednio z systemu plików /proc w systemie Linux.
  • Skrypt GameMemoryMonitor pokazuje, jak połączyć te informacje w celu ciągłego monitorowania i debugowania, w tym jak odpytywać interfejsy API Androida w wątku w tle, aby zapobiec obciążeniu wydajności (ponieważ używanie JNI i odpytywanie informacji o pamięci może być kosztowne), oraz jak łączyć się ze zdarzeniami cyklu życia, takimi jak OnApplicationPause, aby śledzić zmiany pamięci, gdy aplikacja jest w tle lub wznawiana.

Aby używać tych narzędzi, dodaj oba skrypty do folderu Assets i dołącz skrypt GameMemoryMonitor do obiektu GameObject w scenie.

Dokładniejsza ocena

Aby sprawdzić dokładne wartości „anonimowy RSS + przestrzeń wymiany” w systemie operacyjnym Android, użyj narzędzia Perfetto. Umożliwia ono dokładne pomiary wykorzystania pamięci na poziomie systemu i dokładną analizę rozmiaru pamięci gry.

Interfejs Perfetto pokazujący anonimowe zapytania RSS, swap i ich sumę.
Rysunek 2. Interfejs Perfetto pokazujący anonimowy RSS, przestrzeń wymiany i ich sumę.