Informacje o zarządzaniu pamięcią

Optymalizacja pamięci jest kluczowa, aby zapewnić stabilną i wydajną rozgrywkę na Androidzie. Z tego przewodnika dowiesz się, dlaczego wydajne wykorzystanie pamięci jest ważne, jak system operacyjny Android zarządza limitami pamięci procesów i jak je egzekwuje oraz jakie nowe progi są dostępne w Konsoli Google Play, aby pomóc Ci monitorować i poprawiać jakość techniczną gry.

Dlaczego optymalizacja pamięci jest tak ważna

Optymalizacja pamięci gry jest niezbędna, aby utrzymać zainteresowanie graczy, zwiększyć kompatybilność z urządzeniami i zachować zgodność ze standardami jakości platformy:

  • Zapobieganie uruchomieniu „na zimno” (wrażenia użytkownika i utrzymanie): gdy gracz tymczasowo przełącza się z gry (np. aby odpowiedzieć na powiadomienie lub sprawdzić wiadomość), system operacyjny umieszcza proces gry w tle. Jeśli wykorzystanie pamięci w tle przez grę jest zbyt wysokie, mechanizm Low Memory Killer (LMK) systemu priorytetowo zakończy proces gry, aby odzyskać pamięć RAM na potrzeby zadań działających na pierwszym planie. Następnym razem, gdy użytkownik wznowi grę, zamiast płynnego i natychmiastowego wznowienia na ciepło, gra będzie musiała przejść długie uruchomienie „na zimno” – całkowicie przeładować z pamięci masowej zasoby graficzne, dźwięk i pliki binarne silnika gry. Utrzymywanie niskiego wykorzystania pamięci w tle zapobiega tym cichym zakończeniom w tle, zachowując stan użytkownika i zapewniając graczom możliwość natychmiastowego wznowienia sesji. Więcej informacji o działaniu mechanizmu LMK systemu znajdziesz w przewodniku Android Vitals – Low memory killers.
  • Stabilność ekosystemu i urządzenia: nieefektywne wykorzystanie pamięci i wycieki pamięci pogarszają ogólną kondycję systemu. Gdy pamięć systemowa jest ograniczona, system jest poddawany silnej presji, co powoduje spadek liczby klatek na sekundę, zacinanie się interfejsu i problemy z dźwiękiem. Jeśli presja na pamięć jest zbyt duża, mechanizm Low Memory Killer (LMK) systemu agresywnie kończy procesy działające w tle, co powoduje, że inne aplikacje doświadczają powolnego zimnego startu i utraty stanu użytkownika, gdy gracze przełączają się między zadaniami.
  • Zakończenia na poziomie platformy: od Androida 17 (API na poziomie 37) system bardziej aktywnie kończy procesy, które zużywają zbyt dużo pamięci. Jeśli wykorzystanie pamięci przez grę jest zbyt wysokie, system operacyjny może nagle zakończyć jej proces bez generowania standardowego śledzenia stosu.
  • Kompatybilność z urządzeniami: flagowe urządzenia mają od 12 do 16 GB pamięci RAM, ale ogromna część globalnej społeczności graczy korzysta z urządzeń z 4 lub 6 GB pamięci RAM. Prawidłowe zarządzanie pamięcią zapewnia, że gra pozostanie dostępna i responsywna na wszystkich poziomach sprzętu bez konieczności stosowania złożonych, oddzielnych pakietów zasobów.

Pamięć w Androidzie

Aby opracować skuteczne strategie zarządzania pamięcią, deweloperzy muszą wiedzieć, jak platforma Android zarządza pamięcią fizyczną i jak mierzy aktywne wykorzystanie pamięci przez grę.

Podstawowe pojęcia dotyczące pamięci w Androidzie

Podstawowe pojęcia dotyczące zarządzania pamięcią na poziomie platformy znajdziesz w oficjalnej dokumentacji Memory Management Overview. Ten zasób obejmuje 4 obszary architektury:

  • Omówienie pamięci: Android używa stronicowania i mapowania pamięci (mmap) do zarządzania pamięcią RAM. Nie obsługuje tradycyjnego pliku wymiany na dysku. Zamiast tego korzysta z kompresji stron (za pomocą zRAM) i odzyskiwania stron, aby zwolnić pamięć fizyczną.
  • Alokacja pamięci między procesami: Android udostępnia pamięć RAM całemu systemowi. Przydziela określone sterty do wykonywania maszyn wirtualnych Dalvik lub ART, jednocześnie umożliwiając natywnym środowiskom programistycznym (takim jak silniki gier C++) żądanie pamięci z natywnej sterty systemowej.
  • Zarządzanie pamięcią aplikacji: działając w modelu wieloprocesowym, Android oczekuje, że aplikacje będą dynamicznie monitorować stan cyklu życia i dobrowolnie zwalniać niepotrzebne zasoby (takie jak grafika i bitmapy bez pamięci podręcznej), aby wspierać kondycję systemu.
  • Omówienie procesów i wątków: system dzieli procesy na hierarchię na podstawie ich bieżącej widoczności i ważności dla użytkownika, określając, które procesy mają być utrzymywane przy życiu, a które mają być zakończone jako pierwsze w warunkach niskiego poziomu pamięci.

Wskaźnik łącznego wykorzystania pamięci

Ogranicznik pamięci na poziomie platformy Android 17 ocenia zużycie procesów na podstawie łącznego wykorzystania pamięci, a nie łącznego rozmiaru rezydentnego (RSS) ani rozmiaru pamięci wirtualnej.

Łączne wykorzystanie pamięci = anonimowe RSS (RssAnon) + nieskompresowana pamięć wymiany (VmSwap)

Aby uniemożliwić grom przekraczanie limitów wymuszanych przez platformę, deweloperzy muszą dokładnie wiedzieć, co te wskaźniki oznaczają na poziomie systemu. Więcej informacji o tych wskaźnikach, alokacji pamięci RAM i sposobie obsługi stron wspieranych przez pliki znajdziesz w przewodniku Monitorowanie wykorzystania pamięci w sekcji Informacje o wskaźnikach RSS i pamięci wymiany.

Ograniczenia pamięci

Aby zachować stabilność systemu i zapewnić, że aplikacje nie będą zużywać nadmiernej ilości zasobów, platforma Android wymusza limity pamięci dla uruchomionych procesów.

Ogranicznik pamięci w Androidzie 17 i nowszym

Android 17 i nowszy wymusza ścisłe limity pamięci dla poszczególnych aplikacji za pomocą Linux cgroup v2, aby uniemożliwić poszczególnym aplikacjom powodowanie niestabilności w całym systemie. Więcej informacji o implementacji technicznej znajdziesz w przewodniku AOSP Memory Limiter Guide i artykule Prioritizing Memory Efficiency: Essential Steps for Android 17.

  • Mechanizm: ogranicznik pamięci monitoruje wszystkie procesy aplikacji i dynamicznie przypisuje limity na podstawie stanu cyklu życia procesu:
    • Widoczne procesy (pierwszy plan): procesy aplikacji, które obecnie wyświetlają interfejs, powinny mieć większy zestaw roboczy zasobów i mają bardziej liberalny limit.
    • Niewidoczne procesy (tło lub usługi): procesy aplikacji, które wykonują aktywne zadania bez wyświetlania interfejsu, są ograniczone do mniejszego, bardziej restrykcyjnego budżetu.
  • Atrybuty jądra: usługa korzysta z 2 głównych atrybutów:
    • memory.high: miękki limit. Po przekroczeniu tego limitu jądro ogranicza proces i próbuje agresywnie odzyskać pamięć. Odzyskiwanie pamięci może spowodować pogorszenie wydajności gry.
    • memory.swap.max: wymusza twardy limit miejsca na pamięć wymiany lub zRAM, które może wykorzystać proces.
  • Zachowanie po zakończeniu: jeśli proces nadal przydziela anonimową pamięć po przekroczeniu limitu memory.high i wyczerpie pojemność pamięci wymiany, alokacje się nie powiodą, a system operacyjny cicho zakończy proces. To zakończenie jest rejestrowane za pomocą ApplicationExitInfo z przyczyną zakończenia Memory Limiter (dostępne od Androida 17, 26Q4).

Monitorowanie wykorzystania pamięci

Aby skutecznie zoptymalizować pamięć gry, musisz najpierw zrozumieć, jak platforma Android mierzy jej wykorzystanie. Android 17 aktualizuje wskaźnik wymuszania pamięci, aby śledzić sumę anonimowego RSS (RssAnon) i nieskompresowanej pamięci wymiany (VmSwap), z wyłączeniem pamięci wspieranej przez pliki lub prywatnej pamięci GPU. Z tego przewodnika dowiesz się, jak korzystać z narzędzi na poziomie systemu, takich jak Perfetto i meminfo, implementować interfejsy API do diagnostyki, takie jak ProfilingManager i onTrimMemory, oraz wyodrębniać dokładne alokacje pamięci w Unity i Unreal Engine. Dowiedz się, jak dokładnie profilować grę i unikać zacinania się związanego z tradycyjnym odpytywaniem pamięci w czasie działania.

Więcej informacji znajdziesz w artykule Monitorowanie wykorzystania pamięci.

Strategie zmniejszania wykorzystania pamięci

Silniki gier upraszczają tworzenie aplikacji na wielu platformach, ale ich domyślna obsługa pamięci może powodować przekroczenie limitów pamięci na poziomie systemu operacyjnego. Na tej stronie znajdziesz praktyczne wskazówki dotyczące optymalizacji dostosowane do Unity i Unreal Engine. Dowiedz się, dlaczego poleganie na onTrimMemory opartym na Javie może powodować zakleszczenia w Unity i jak zamiast tego używać natywnych wywołań zwrotnych cyklu życia. Poznasz też kluczowe optymalizacje na poziomie zasobów, takie jak używanie kompresji tekstur ASTC 8x8 i konfigurowanie zwalniania zasobów, aby gra działała płynnie na wszystkich poziomach sprzętu.