Zrób zrzut stosu

Zrób zrzut sterty, aby zobaczyć, które obiekty w aplikacji zużywają pamięć w momencie zrzutu, i wykryć wycieki pamięci lub zachowanie związane z alokacją pamięci, które prowadzi do zacinania się, zawieszania, a nawet awarii aplikacji. Jest to szczególnie przydatne po dłuższej sesji użytkownika, gdy może pokazywać obiekty, które nadal znajdują się w pamięci, a nie powinny już tam być.

Na tej stronie opisujemy narzędzia, które Android Studio udostępnia do zbierania i analizowania zrzutów sterty. Możesz też sprawdzić pamięć aplikacji z poziomu wiersza poleceń za pomocą polecenia dumpsys, a także wyświetlić zdarzenia czyszczenia pamięci (GC) w Logcat.

Dlaczego warto profilować pamięć aplikacji

Android zapewnia zarządzane środowisko pamięci – gdy Android stwierdzi, że aplikacja nie używa już niektórych obiektów, moduł odśmiecania zwalnia nieużywaną pamięć i przywraca ją do sterty. Sposób, w jaki Android wyszukuje nieużywaną pamięć, jest stale ulepszany, ale w pewnym momencie we wszystkich wersjach Androida system musi na chwilę wstrzymać Twój kod. Zazwyczaj przerwy są niezauważalne. Jeśli jednak aplikacja przydziela pamięć szybciej, niż system jest w stanie ją odzyskać, może dojść do opóźnienia w jej działaniu, ponieważ moduł odzyskiwania pamięci będzie musiał zwolnić wystarczającą ilość pamięci, aby zaspokoić potrzeby aplikacji. Opóźnienie może spowodować pomijanie klatek przez aplikację i widoczne spowolnienie.

Nawet jeśli aplikacja nie działa wolno, może wyciekać z niej pamięć, która jest zachowywana nawet wtedy, gdy aplikacja działa w tle. Takie zachowanie może spowolnić działanie pozostałej części systemu, ponieważ wymusza niepotrzebne zdarzenia czyszczenia pamięci. W końcu system musi zakończyć proces aplikacji, aby odzyskać pamięć. Gdy użytkownik wróci do aplikacji, proces aplikacji musi zostać całkowicie ponownie uruchomiony.

Informacje o praktykach programistycznych, które mogą zmniejszyć zużycie pamięci przez aplikację, znajdziesz w artykule Zarządzanie pamięcią aplikacji.

Omówienie zrzutu stosu

Aby zarejestrować zrzut stosu, wybierz zadanie Analizuj wykorzystanie pamięci (zrzut stosu) (użyj programu profilującego: uruchom „aplikację” w trybie z możliwością debugowania (pełne dane)). Podczas zrzucania sterty ilość pamięci Javy może tymczasowo wzrosnąć. To normalne, ponieważ zrzut stosu jest tworzony w tym samym procesie co aplikacja i do zebrania danych wymaga pewnej ilości pamięci. Po przechwyceniu zrzutu sterty zobaczysz:

Widok zrzutu sterty w profilerze Android Studio.

Lista zajęć zawiera te informacje:

  • Przydziały: liczba przydziałów w stercie.
  • Rozmiar natywny: łączna ilość pamięci natywnej używanej przez ten typ obiektu (w bajtach). W przypadku niektórych obiektów przydzielonych w Javie zobaczysz tutaj pamięć, ponieważ Android używa pamięci natywnej w przypadku niektórych klas platformy, takich jak Bitmap.

  • Shallow Size (Rozmiar płytki): łączna ilość pamięci Javy używanej przez ten typ obiektu (w bajtach).

  • Zachowany rozmiar: łączny rozmiar pamięci zachowanej z powodu wszystkich instancji tej klasy (w bajtach).

Użyj menu sterty, aby odfiltrować określone sterty:

  • Stos aplikacji (domyślny): główny stos, na którym aplikacja przydziela pamięć.
  • Stos obrazów: obraz rozruchowy systemu zawierający klasy wstępnie wczytywane podczas uruchamiania. Przydziały w tym miejscu nigdy nie są przenoszone ani usuwane.
  • Stos Zygote: stos kopiowany przy zapisie, z którego proces aplikacji jest rozwidlany w systemie Android.

W menu wybierz sposób rozmieszczenia przydziałów:

  • Uporządkuj według zajęć (domyślnie): grupuje wszystkie przydziały na podstawie nazwy zajęć.
  • Uporządkuj według pakietu: grupuje wszystkie przydziały na podstawie nazwy pakietu.

Użyj menu zajęć, aby odfiltrować grupy zajęć:

  • Wszystkie klasy (domyślnie): wyświetla wszystkie klasy, w tym klasy z bibliotek i zależności.
  • Pokaż wycieki aktywności/fragmentów: pokazuje klasy, które powodują wycieki pamięci.
  • Pokaż klasy projektu: wyświetla tylko klasy zdefiniowane przez Twój projekt.

Kliknij nazwę klasy, aby otworzyć panel Instancja. Każda wymieniona instancja zawiera te elementy:

  • Głębokość: najmniejsza liczba przeskoków od dowolnego korzenia GC do wybranej instancji.
  • Rozmiar natywny: rozmiar tej instancji w pamięci natywnej. Ta kolumna jest widoczna tylko na urządzeniach z Androidem 7.0 lub nowszym.
  • Shallow Size (Rozmiar płytki): rozmiar tej instancji w pamięci Javy.
  • Retained Size (Rozmiar zachowany): rozmiar pamięci, którą zajmuje ta instancja (zgodnie z drzewem dominatorów).

Kliknij instancję, aby wyświetlić szczegóły instancji, w tym jej pola i odwołania. Typowe typy pól i odwołań to typy strukturalne, tablice i proste typy danych w języku Java. Kliknij prawym przyciskiem myszy pole lub odwołanie, aby przejść do powiązanego wystąpienia lub wiersza w kodzie źródłowym.

  • Pola: wyświetla wszystkie pola w tej instancji.
  • Odwołania: pokazuje wszystkie odwołania do obiektu wyróżnionego na karcie Instancja.
Widoki Instancje, PolaOdwołania w oknie narzędzia Zrzut sterty.

Wykrywanie wycieków pamięci

Aby szybko odfiltrować klasy, które mogą być powiązane z wyciekami pamięci, otwórz menu klas i kliknij Pokaż wycieki aktywności lub fragmentów. Android Studio wyświetla klasy, które według niego wskazują wycieki pamięci w przypadku instancji ActivityFragment w Twojej aplikacji.

Aby ręcznie wyszukać wycieki pamięci, przejrzyj listy klas i instancji, aby znaleźć obiekty o dużym rozmiarze zachowanym. Wyszukaj wycieki pamięci spowodowane przez:

  • Długotrwałe odwołania do Activity lub Context, które mogą ujawniać wykres kompozycji Compose hostowanej (np. ComposeView i jego kompozycje podrzędne).
  • Wyciekające obiekty stanu Jetpack Compose (MutableState), elementy przechowujące stan lub lambdy, które przechwytują Context.
  • Zapominanie o usunięciu detektorów lub obserwatorów w bloku onDispose funkcji DisposableEffect.
  • Klasy wewnętrzne inne niż statyczne, np. a Runnable, które mogą zawierać instancję Activity.
  • pamięci podręczne, które przechowują obiekty dłużej niż jest to konieczne;

Gdy znajdziesz potencjalne wycieki pamięci, użyj kart PolaOdwołania w sekcji Szczegóły instancji, aby przejść do interesującej Cię instancji lub wiersza kodu źródłowego.

Wywoływanie wycieków pamięci na potrzeby testów

Aby przeanalizować wykorzystanie pamięci, obciąż kod aplikacji i spróbuj wymusić wycieki pamięci. Jednym ze sposobów wywołania wycieków pamięci w aplikacji jest pozostawienie jej na jakiś czas, a następnie sprawdzenie sterty. Wycieki mogą przedostawać się na górę przydziałów w stercie. Im mniejszy wyciek, tym dłużej musisz uruchamiać aplikację, aby go zobaczyć.

Wyciek pamięci możesz też wywołać na jeden z tych sposobów:

  • Obróć urządzenie z pozycji pionowej do poziomej i z powrotem kilka razy, gdy jest w różnych stanach aktywności. Obracanie urządzenia może często powodować wyciek pamięci w aplikacji, jeśli aplikacja przechowuje odwołanie do Activity lub Context w operacjach asynchronicznych lub w obiektach przechowujących stan. W takim przypadku wycieka też Activity (a w konsekwencji drzewo interfejsu Compose hostowane przez ten obiekt i powiązane z nim drzewa stanu).
  • Przełączanie się między aplikacją a inną aplikacją w różnych stanach aktywności. Na przykład przejdź do ekranu głównego, a potem wróć do aplikacji.

Eksportowanie i importowanie nagrania zrzutu sterty

Możesz eksportować i importować plik zrzutu stosu na karcie Poprzednie nagrania w programie profilującym. Android Studio zapisuje nagranie jako plik .hprof.

Jeśli chcesz użyć innego analizatora plików .hprof, np. jhat, musisz przekonwertować plik .hprof z formatu Androida na format pliku .hprof Java SE. Aby przekonwertować format pliku, użyj narzędzia hprof-conv znajdującego się w katalogu {android_sdk}/platform-tools/. Uruchom polecenie hprof-conv z 2 argumentami: oryginalną nazwą pliku .hprof i lokalizacją, w której ma zostać zapisany przekonwertowany plik .hprof, w tym nową nazwą pliku .hprof. Przykład:

hprof-conv heap-original.hprof heap-converted.hprof

Dodatkowe materiały