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 ją wyłączając. Więcej informacji o tych optymalizacjach znajdziesz w artykule Przydzielanie pamięci między procesami.
Na tej stronie znajdziesz informacje o tym, jak uniknąć sytuacji, w których gra ma za mało pamięci.
Reagowanie na wywołanie metody onTrimMemory()
System używa onTrimMemory()
, aby powiadamiać aplikację o zdarzeniach związanych z cyklem życia, które stanowią dobrą okazję do dobrowolnego zmniejszenia zużycia pamięci i uniknięcia zamknięcia przez proces LMK 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ą zużycie pamięci po przejściu w tle, rzadziej są zamykane w tle.
W odpowiedzi na zdarzenia przycinania najlepiej jest 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, które zostały zdekodowane z lokalnie przechowywanych skompresowanych obrazów, często warto przyciąć lub wyczyścić tę pamięć podręczną w odpowiedzi na 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. } } } }
C#
using UnityEngine; using System.Collections; using System.Collections.Generic; class LowMemoryTrigger : MonoBehaviour { private void Start() { Application.lowMemory += OnLowMemory; } private void OnLowMemory() { // Respond to low memory condition (e.g., Resources.UnloadUnusedAssets()) } }
Oszczędne korzystanie z budżetów pamięci
Oszczędnie gospodaruj pamięcią, aby uniknąć jej wyczerpania. Oto kilka kwestii, które warto wziąć pod uwagę:
- Rozmiar fizycznej pamięci RAM: gry często wykorzystują od ¼ do ½ fizycznej pamięci RAM urządzenia.
- Maksymalny rozmiar zRAM: większa ilość zRAM oznacza, że gra może mieć więcej pamięci do przydzielenia. Ta kwota może się różnić w zależności od urządzenia. Aby ją sprawdzić, poszukaj symbolu
SwapTotal
w/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.
- Zużycie 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 przestrzegania konserwatywnego 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 sygnał onTrimMemory()
możesz przydzielić tekstury o niższej rozdzielczości lub przechowywać mniejszą liczbę shaderów. Dynamiczne przydzielanie 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ć działanie gry.
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
MemoryInfo
z 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 pakiet narzędzi do zbierania informacji o wydajności i pamięci urządzenia 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ć na tych danych zapytania SQL na potrzeby przetwarzania offline. Włącz długie ślady w aplikacji do śledzenia systemu. Upewnij się, że w śladzie jest włączona kategoria pamięć:Pamięć.
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, pokazując, gdzie została ona 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łędzie
bugreport
to narzędzie do rejestrowania informacji, 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.