Zrób zrzut stosu

Zrób zrzut sterty, aby sprawdzić, które obiekty w aplikacji zużywają pamięć w momencie zrzutu, i zidentyfikować wycieki pamięci lub zachowanie związane z alokacją pamięci które prowadzi do zacinania się, zawieszania, a nawet awarii aplikacji. Szczególnie przydatne jest robienie zrzutów sterty po dłuższej sesji użytkownika, gdy może to pokazać 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 wiersza poleceń za pomocą polecenia dumpsys oraz zobaczyć zdarzenia odśmiecania pamięci (GC) w Logcat.

Dlaczego warto profilować pamięć aplikacji

Android udostępnia zarządzane środowisko pamięci – gdy Android stwierdzi, że aplikacja nie używa już niektórych obiektów, odśmiecacz zwalnia nieużywaną pamięć z powrotem do sterty. Sposób, w jaki Android znajduje nieużywaną pamięć, jest stale ulepszany, ale w pewnym momencie we wszystkich wersjach Androida system musi na chwilę wstrzymać Twój kod. W większości przypadków przerwy są niezauważalne. Jeśli jednak aplikacja alokuje pamięć szybciej, niż system może ją zbierać, aplikacja może się opóźniać, gdy odśmiecacz zwalnia wystarczającą ilość pamięci, aby zaspokoić alokacje. Opóźnienie może spowodować, że aplikacja będzie pomijać klatki i widocznie spowolnić działanie.

Nawet jeśli aplikacja nie wykazuje spowolnienia, ale ma wycieki pamięci, może zachować tę pamięć, nawet gdy działa w tle. Takie zachowanie może spowolnić działanie pamięci w pozostałej części systemu, wymuszając niepotrzebne zdarzenia odśmiecania pamięci. W końcu system jest zmuszony do zamknięcia procesu aplikacji, aby odzyskać pamięć. Gdy użytkownik wróci do aplikacji, proces aplikacji musi zostać całkowicie uruchomiony ponownie.

Więcej informacji o praktykach programistycznych, które mogą zmniejszyć zużycie pamięci przez aplikację , znajdziesz w artykule [Manage your app's memory]memory.

Omówienie zrzutu sterty

Aby zrobić zrzut sterty, wybierz zadanie Analyze Memory Usage (Heap Dump) (użyj Profiler: run 'app' as debuggable (complete data)), aby zrobić zrzut sterty. Podczas zrzutu sterty ilość pamięci Javy może tymczasowo wzrosnąć. Jest to normalne, ponieważ zrzut sterty odbywa się w tym samym procesie co aplikacja i wymaga pewnej ilości pamięci do zebrania danych. Po zrobieniu zrzutu sterty zobaczysz te informacje:

Widok zrzutu sterty w Profilerze Android Studio.

Lista klas zawiera te informacje:

  • Allocations (Alokacje): liczba alokacji w stercie.
  • Native Size (Rozmiar natywny): łączna ilość pamięci natywnej używanej przez ten typ obiektu (w bajtach). W przypadku niektórych obiektów alokowanych w Javie zobaczysz tutaj pamięć, ponieważ Android używa pamięci natywnej w przypadku niektórych klas frameworka, np. Bitmap.

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

  • Rozmiar zachowany: łączny rozmiar pamięci zachowanej ze względu na wszystkie instancje tej klasy (w bajtach).

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

  • App heap (default) (Stos aplikacji (domyślnie)): główny stos, na którym aplikacja alokuje pamięć.
  • Image heap (Stos obrazu): obraz rozruchowy systemu zawierający klasy, które są wstępnie ładowane podczas uruchamiania. Alokacje w tym miejscu nigdy się nie przenoszą ani nie znikają.
  • Zygote heap (Stos Zygote): stos kopiowany przy zapisie, z którego w systemie Android rozwidla się proces aplikacji.

Użyj menu Arrangement (Rozmieszczenie), aby wybrać sposób rozmieszczenia alokacji:

  • Arrange by class (default) (Rozmieść według klasy (domyślnie)): grupuje wszystkie alokacje na podstawie nazwy klasy.
  • Arrange by package (Rozmieść według pakietu): grupuje wszystkie alokacje na podstawie nazwy pakietu.

Użyj menu Class (Klasa), aby odfiltrować grupy klas:

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

Kliknij nazwę klasy, aby otworzyć panel Instance (Instancja). Każda instancja na liście zawiera te informacje:

  • Depth (Głębokość): najkrótsza liczba przeskoków od dowolnego korzenia GC do wybranej instancji.
  • Native Size (Rozmiar natywny): rozmiar tej instancji w pamięci natywnej. Ta kolumna jest widoczna tylko w Androidzie 7.0 i nowszym.
  • Shallow Size (Rozmiar płytki): rozmiar tej instancji w pamięci Javy.
  • Retained Size (Rozmiar zachowany): rozmiar pamięci, którą ta instancja dominuje (zgodnie z drzewem dominatorów).

Kliknij instancję, aby wyświetlić Instance Details (Szczegóły instancji), w tym Fields (Pola) i References (Odwołania). Typowe typy pól i odwołań to typy strukturalne , tablice , i podstawowe typy danych w Javie. Kliknij pole lub odwołanie prawym przyciskiem myszy, aby przejść do powiązanej instancji lub wiersza w kodzie źródłowym.

  • Fields (Pola): pokazuje wszystkie pola w tej instancji.
  • References (Odwołania): pokazuje wszystkie odwołania do obiektu wyróżnionego na karcie Instance (Instancja).
Widoki Instances (Instancje), Fields (Pola) i References (Odwołania) w oknie narzędzia Heap Dump (Zrzut sterty).

Wykrywanie zduplikowanych bitmap

Od Androida Studio Narwhal 4 możesz też wykrywać zbędne bitmapy w widoku zrzutu sterty.

Oto jak je znaleźć:

  1. Otwórz kartę Profiler w Android Studio.
  2. Kliknij Heap Dump (Zrzut sterty) lub Analyze Memory Usage (Analizuj zużycie pamięci) i kliknij nagraj, aby zrobić migawkę bieżącego stanu pamięci aplikacji.
  3. Przeskanuj wyniki analizy pod kątem żółtego trójkąta ostrzegawczego ⚠️, którego Android Studio używa do oznaczania zduplikowanych bitmap przechowywanych wielokrotnie.
    • Możesz też przejść do nagłówka profilera, wybrać Filter by (Filtruj według) i kliknąć ustawienie Duplicate Bitmaps (Zduplikowane bitmapy).
  4. Kliknij dowolny oznaczony wpis, aby otworzyć panel Bitmap Preview (Podgląd bitmapy), który pozwoli Ci dokładnie zobaczyć, który obraz jest powtarzany.
  5. Użyj tego wizualnego potwierdzenia, aby znaleźć zbędną logikę ładowania w kodzie i wdrożyć lepszą strategię buforowania.
Szukaj zduplikowanych bitmap za pomocą żółtego trójkąta ostrzegawczego ⚠️.

Znajdowanie wycieków pamięci

Aby szybko odfiltrować klasy, które mogą być powiązane z wyciekami pamięci, otwórz menu Class (Klasa) i wybierz Show activity/fragment leaks (Pokaż wycieki aktywności/fragmentów). Android Studio pokazuje klasy, które według niego wskazują na wycieki pamięci w przypadku Activity i Fragment instancji w aplikacji.

Aby ręcznie wyszukać wycieki pamięci, przejrzyj listy klas i instancji, aby znaleźć obiekty o dużym Retained Size (Rozmiar zachowany). Szukaj wycieków pamięci spowodowanych przez jedną z tych przyczyn:

  • Długotrwałe odwołania do Activity lub Context, które mogą powodować wyciek hostowanego wykresu kompozycji Compose (np. ComposeView i jego podkompozycji).
  • Wyciekające obiekty stanu Jetpack Compose (MutableState), kontenery stanu lub lambdy, które przechwytują Context.
  • Zapominanie o czyszczeniu odbiorników lub obserwatorów w bloku onDispose elementu DisposableEffect.
  • Niestatyczne klasy wewnętrzne, takie jak 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 Fields (Pola) i References (Odwołania) w sekcji Instance Details (Szczegóły instancji), aby przejść do interesującej Cię instancji lub wiersza kodu źródłowego.

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

Aby przeanalizować wykorzystanie pamięci, musisz obciążyć kod aplikacji i spróbować wymusić wycieki pamięci. Jednym ze sposobów na wywołanie wycieków pamięci w aplikacji jest jej uruchomienie na jakiś czas przed sprawdzeniem sterty. Wycieki mogą się pojawiać na początku alokacji w stercie. Im mniejszy wyciek, tym dłużej musisz uruchamiać aplikację, aby go zobaczyć.

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

  • Wielokrotnie obracaj urządzenie z orientacji pionowej do poziomej i z powrotem w różnych stanach aktywności. Obracanie urządzenia może często powodować wyciek Activity (a w konsekwencji hostowanego drzewa interfejsu Compose i powiązanych drzew stanu), jeśli aplikacja zawiera odwołanie do Activity lub Context w operacjach asynchronicznych lub kontenerach stanu.
  • Przełączaj 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

Plik zrzutu sterty możesz eksportować i importować z karty Past Recordings (Poprzednie nagrania) w profilerze. 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