Na platformie Android system próbuje wykorzystać jak najwięcej pamięci systemowej (RAM) i w razie potrzeby przeprowadza różne optymalizacje pamięci, aby zwolnić miejsce. Te optymalizacje mogą negatywnie wpłynąć na grę, spowalniając ją lub całkowicie wyłączając. Więcej informacji o tych optymalizacjach znajdziesz w temacie Alokacja pamięci między procesami.
Aby zapewnić stabilność urządzenia, od Androida 17 (poziom API 37) system zaczyna wymuszać limity pamięci aplikacji na podstawie łącznej ilości pamięci RAM urządzenia. Jeśli aplikacja przekroczy te limity, Android zakończy proces bez powiązanego śladu stosu.
Na tej stronie znajdziesz informacje o tym, jak uniknąć sytuacji, w których gra działa wolno z powodu małej ilości pamięci.
Reagowanie na wywołanie metody onTrimMemory()
System używa onTrimMemory(), aby powiadamiać aplikację o zdarzeniach cyklu życia, które stwarzają dobrą okazję do dobrowolnego zmniejszenia wykorzystania pamięci i uniknięcia zamknięcia przez proces LMK (low-memory killer) w celu zwolnienia pamięci na potrzeby innych aplikacji.
Jeśli aplikacja zostanie zamknięta w tle, przy następnym uruchomieniu użytkownik doświadczy powolnego uruchomienia „na zimno”. Aplikacje, które zmniejszają wykorzystanie pamięci po przejściu do działania w tle, rzadziej są zamykane w tle.
W odpowiedzi na zdarzenia przycinania najlepiej zwalniać duże przydziały pamięci, które nie są od razu potrzebne i można je w razie potrzeby odtworzyć. Jeśli na przykład aplikacja ma pamięć podręczną map bitowych zdekodowanych z lokalnie przechowywanych skompresowanych obrazów, często warto przyciąć lub wyczyścić tę pamięć podręczną w odpowiedzi na zdarzenie TRIM_MEMORY_UI_HIDDEN.
Kotlin
class MainActivity : AppCompatActivity(), ComponentCallbacks2 { override fun onTrimMemory(level: Int) { if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } }
Java
public class MainActivity extends AppCompatActivity implements ComponentCallbacks2 { public void onTrimMemory(int level) { switch (level) { if (level >= ComponentCallbacks2.TRIM_MEMORY_UI_HIDDEN) { // Release memory related to UI elements, such as bitmap caches. } if (level >= ComponentCallbacks2.TRIM_MEMORY_BACKGROUND) { // Release memory related to background processing, such as by // closing a database connection. } } } }
Oszczędzaj pamięć
Zarezerwuj pamięć z dużym marginesem, aby uniknąć jej wyczerpania. Weź pod uwagę te kwestie:
- Rozmiar fizycznej pamięci RAM: gry często wykorzystują od ¼ do ½ fizycznej pamięci RAM urządzenia.
- Maksymalny rozmiar zRAM: większa pamięć zRAM oznacza, że gra może mieć więcej pamięci do przydzielenia. Ta wartość może się różnić w zależności od urządzenia. Aby ją sprawdzić, poszukaj symbolu
SwapTotalw/proc/meminfo. - Wykorzystanie pamięci przez system operacyjny: urządzenia, które przeznaczają więcej pamięci RAM na procesy systemowe, pozostawiają mniej pamięci na grę. System zamyka proces gry przed zamknięciem procesów systemowych.
- Wykorzystanie pamięci przez zainstalowane aplikacje: przetestuj grę na urządzeniach, na których jest zainstalowanych wiele aplikacji. Aplikacje mediów społecznościowych i komunikatory muszą działać nieustannie, co wpływa na ilość wolnej pamięci.
Jeśli nie możesz się zobowiązać do zachowawczego budżetu pamięci, zastosuj bardziej elastyczne podejście. Jeśli system napotka problemy z małą ilością pamięci, zmniejsz ilość pamięci używanej przez grę. Na przykład w odpowiedzi na onTrimMemory() przydzielaj tekstury o niższej rozdzielczości lub przechowuj mniej shaderów. To dynamiczne podejście do przydzielania pamięci wymaga więcej pracy od dewelopera, zwłaszcza na etapie projektowania gry.
Unikanie thrashingu
Thrashing występuje, gdy ilość wolnej pamięci jest mała, ale nie na tyle, aby zakończyć grę.
W takiej sytuacji kswapd odzyskał strony, których gra nadal potrzebuje, więc próbuje ponownie załadować je z pamięci. Nie ma wystarczająco dużo miejsca, więc strony są ciągle zamieniane (ciągłe zamienianie).
Śledzenie systemu zgłasza tę sytuację jako wątek, w którym kswapd działa w sposób ciągły.
Jednym z objawów thrashingu są długie czasy klatek – nawet sekunda lub więcej. Zmniejsz wykorzystanie pamięci przez grę, aby rozwiązać ten problem.
Korzystanie z dostępnych narzędzi
Android ma zestaw narzędzi, które pomagają zrozumieć, jak system zarządza pamięcią.
Meminfo
To narzędzie zbiera statystyki pamięci, aby pokazać, ile pamięci PSS zostało przydzielone i w jakich kategoriach było używane.
Wydrukuj statystyki meminfo na jeden z tych sposobów:
- Użyj polecenia
adb shell dumpsys meminfo package-name. - Użyj wywołania
MemoryInfoz interfejsu Android Debug API.
Statystyka PrivateDirty pokazuje ilość pamięci RAM w procesie, która nie może być przeniesiona na dysk i nie jest udostępniana innym procesom. Większość tej ilości staje się dostępna dla systemu po zakończeniu tego procesu.
Punkty śledzenia pamięci
Punkty śledzenia pamięci śledzą ilość pamięci RSS wykorzystywanej przez grę. Obliczanie wykorzystania pamięci RSS jest znacznie szybsze niż obliczanie wykorzystania pamięci PSS. Wartość RSS jest szybsza do obliczenia, dlatego pokazuje większą szczegółowość zmian rozmiaru pamięci, co pozwala dokładniej mierzyć szczytowe wykorzystanie pamięci. Dzięki temu łatwiej zauważyć skoki, które mogą spowodować wyczerpanie pamięci gry.
Perfetto i długie ślady
Perfetto to zestaw narzędzi do zbierania informacji o wydajności i pamięci na urządzeniu oraz wyświetlania ich w interfejsie internetowym. Obsługuje dowolnie długie ślady, dzięki czemu możesz zobaczyć, jak zmienia się RSS w czasie. Możesz też wykonywać zapytania SQL dotyczące danych, które generuje, w celu przetwarzania offline. Włącz długie ślady w aplikacji Śledzenie systemu. Upewnij się, że w przypadku śladu włączona jest kategoria pamięć:Pamięć. W przypadku niestandardowych instrumentów pamięciowych w trakcie programowania i testowania możesz też używać (wersji beta) interfejsu heapprofd API.
heapprofd
heapprofd to narzędzie do śledzenia pamięci, które jest częścią Perfetto. To narzędzie może pomóc w znalezieniu wycieków pamięci, ponieważ pokazuje, gdzie pamięć została przydzielona za pomocą funkcji malloc. heapprofd można uruchomić za pomocą skryptu w języku Python. Narzędzie to ma niewielkie obciążenie, więc nie wpływa na wydajność tak jak inne narzędzia, np. Malloc Debug.
raport o błędach
bugreport to narzędzie do rejestrowania, które pozwala sprawdzić, czy gra uległa awarii z powodu braku pamięci. Dane wyjściowe narzędzia są znacznie bardziej szczegółowe niż w przypadku logcat. Jest to przydatne do debugowania pamięci, ponieważ pokazuje, czy gra uległa awarii z powodu wyczerpania pamięci, czy została zamknięta przez LMK.
Więcej informacji znajdziesz w artykule Przechwytywanie i odczytywanie raportów o błędach.