Informacje o zarządzaniu pamięcią

Optymalizacja pamięci ma kluczowe znaczenie dla zapewnienia stabilnej i wydajnej rozgrywki 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 oraz jakie nowe wskaźniki pamięci 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, systemowy mechanizm Low Memory Killer (LMK) priorytetowo zakończy proces gry, aby odzyskać pamięć RAM na potrzeby zadań działających na pierwszym planie. 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 ponownie załaduje z pamięci masowej duże 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 systemowego mechanizmu LMK 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 dużemu obciążeniu, co powoduje spadek liczby klatek na sekundę, zacinanie się interfejsu i problemy z dźwiękiem. Jeśli obciążenie pamięci jest zbyt duże, systemowy mechanizm Low Memory Killer (LMK) agresywnie kończy procesy działające w tle, co powoduje, że inne aplikacje muszą przechodzić powolny zimny start i tracą stan użytkownika, gdy gracze przełączają się między zadaniami.
  • Zakończenia na poziomie platformy: od Androida 17 (poziom interfejsu API 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 śladu 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.

Informacje o pamięci 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 informacje o zarządzaniu pamięcią na poziomie platformy znajdziesz w oficjalnej dokumentacji Przegląd zarządzania pamięcią. 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 na potrzeby 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 niebuforowane grafiki i mapy bitowe), aby zachować 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 z punktu widzenia 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 Androida 17 na poziomie platformy ocenia zużycie procesów za pomocą wskaźnika łącznego wykorzystania pamięci, a nie łącznego rozmiaru rezydentnego (RSS) ani rozmiaru pamięci wirtualnej.

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

Aby zapobiec przekraczaniu przez gry limitów platformy, 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 zarządza limitami pamięci dla uruchomionych procesów.

Ogranicznik pamięci w Androidzie 17 i nowszych wersjach

Android 17 (poziom interfejsu API 37) i nowsze wersje zarządzają ścisłymi limitami pamięci dla poszczególnych aplikacji za pomocą cgroup v2 systemu Linux, aby zapobiec powodowaniu przez poszczególne aplikacje 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 aktywnie działają 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 jego przekroczeniu jądro ogranicza proces i próbuje agresywnie odzyskać pamięć. Odzyskiwanie może spowodować pogorszenie wydajności gry.
    • memory.swap.max: zarządza twardym limitem miejsca w pamięci wymiany lub zRAM, które może wykorzystywać proces.
  • Działanie 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 pamięci, aby śledzić sumę anonimowej pamięci 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 systemowych, 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 w 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.

Więcej informacji znajdziesz w artykule Zmniejsz zużycie pamięci.