Przechwyć zrzut sterty, aby zobaczyć, które obiekty w aplikacji zużywają pamięć w momencie przechwytywania, i zidentyfikować wycieki pamięci lub zachowanie alokacji pamięci, które prowadzi do zacinania się, zawieszania, a nawet awarii aplikacji. Szczególnie przydatne jest wykonywanie zrzutów sterty po dłuższej sesji użytkownika, ponieważ mogą one pokazać obiekty, które nadal znajdują się w pamięci, choć nie powinno ich tam być.
Na tej stronie opisujemy narzędzia dostępne w Android Studio, które umożliwiają zbieranie i analizowanie zrzutów stosu. Możesz też sprawdzić pamięć aplikacji z poziomu wiersza poleceń za pomocą dumpsys, a także wyświetlić zdarzenia czyszczenia pamięci 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 pamięci 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ć kod. W większości przypadków przerwy są niezauważalne. Jeśli jednak aplikacja przydziela pamięć szybciej, niż system może ją zbierać, może dojść do opóźnienia, gdy moduł zbierający będzie zwalniać wystarczającą ilość pamięci, aby zaspokoić potrzeby aplikacji. Opóźnienie może spowodować, że aplikacja będzie pomijać klatki, co może być widoczne jako spowolnienie.
Nawet jeśli aplikacja nie działa wolno, ale wycieka z niej pamięć, może ona zachować tę pamięć, nawet gdy działa w tle. Może to spowolnić działanie pamięci reszty systemu przez wymuszanie niepotrzebnych zdarzeń czyszczenia pamięci. W końcu system jest zmuszony do zakończenia procesu aplikacji, aby odzyskać pamięć. Gdy użytkownik wróci do aplikacji, proces aplikacji musi zostać całkowicie uruchomiony ponownie.
Informacje o praktykach programistycznych, które mogą zmniejszyć wykorzystanie pamięci przez aplikację, znajdziesz w artykule o [zarządzaniu pamięcią aplikacji]memory.
Omówienie zrzutu stosu
Aby przechwycić zrzut stosu, wybierz zadanie Analizuj wykorzystanie pamięci (zrzut stosu) (użyj opcji Profiler: uruchom „aplikację” z możliwością debugowania (pełne dane)). Podczas zrzutu sterty ilość pamięci Java może tymczasowo wzrosnąć. Jest to normalne, ponieważ zrzut stosu występuje w tym samym procesie co aplikacja i wymaga trochę pamięci do zebrania danych. Po przechwyceniu zrzutu sterty zobaczysz te informacje:
Lista zajęć zawiera te informacje:
- Alokacje: liczba alokacji na stercie.
Rozmiar natywny: łączna ilość pamięci natywnej używanej przez ten typ obiektu (w bajtach). Zobaczysz tu pamięć dla niektórych obiektów przydzielonych w języku Java, ponieważ Android używa pamięci natywnej dla niektórych klas platformy, takich jak
Bitmap.Zajęte miejsce: łączna ilość pamięci Java używanej przez ten typ obiektu (w bajtach).
Zwolnione miejsce: łączny rozmiar pamięci, która zostanie zwolniona po usunięciu 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ęć.
- Sterta obrazu: obraz rozruchowy systemu zawierający klasy, które są wstępnie wczytywane podczas uruchamiania. Przydziały tutaj nigdy nie są przenoszone ani usuwane.
- Sterta Zygote: sterta typu „kopiowanie przy zapisie”, z której w systemie Android jest rozgałęziany proces aplikacji.
W menu układu wybierz sposób rozmieszczenia przydziałów:
- Porządkuj według zajęć (domyślnie): grupuje wszystkie przydziały według nazwy zajęć.
- Uporządkuj według pakietu: grupuje wszystkie przydziały według nazwy pakietu.
Użyj menu zajęć, aby filtrować grupy zajęć:
- Wszystkie klasy (domyślnie): wyświetla wszystkie klasy, w tym te 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 instancja na liście zawiera te informacje:
- 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 w przypadku Androida 7.0 lub nowszego.
- Zajęte miejsce: rozmiar tej instancji w pamięci Javy.
- Zwolnione miejsce: 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 podstawowe 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.
- References (Odwołania): pokazuje wszystkie odwołania do obiektu wyróżnionego na karcie Instance (Instancja).
Wykrywanie zduplikowanych bitmap
Począwszy od Android Studio Narwhal 4, możesz też wykrywać nadmiarowe bitmapy w widoku zrzutu stosu.
Oto jak je znaleźć:
- Otwieranie karty Profiler w Android Studio
- Kliknij Zrzut stosu (lub Analizuj wykorzystanie pamięci) i kliknij Nagraj, aby zrobić zrzut bieżącego stanu pamięci aplikacji.
- Przeszukaj 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ć Filtruj według: i kliknąć ustawienie Zduplikowane bitmapy.
- Kliknij dowolny wpis oznaczony flagą, aby otworzyć panel Podgląd mapy bitowej, w którym możesz zobaczyć, który obraz jest powtarzającym się problemem.
- Użyj tego wizualnego potwierdzenia, aby znaleźć w kodzie zbędną logikę wczytywania i wdrożyć lepszą strategię buforowania.
Znajdowanie wycieków pamięci
Aby szybko odfiltrować klasy, które mogą być powiązane z wyciekami pamięci, otwórz menu klas i wybierz Pokaż wycieki aktywności/fragmentów. Android Studio wyświetla klasy, które według niego wskazują na wycieki pamięci w przypadku instancji Activity i Fragment w aplikacji.
Aby ręcznie wyszukać wycieki pamięci, przejrzyj listy klas i instancji, aby znaleźć obiekty o dużym zwolnionym miejscu. Poszukaj wycieków pamięci spowodowanych przez:
- Długotrwałe odwołania do
ActivitylubContext, które mogą ujawnić hostowany graf kompozycji Compose (np.ComposeViewi jego podkompozycje). - Wyciek obiektów stanu Jetpack Compose (
MutableState), zmiennych stanu lub funkcji lambda, które przechwytująContext. - Zapominanie o wyczyszczeniu detektorów lub obserwatorów w bloku
onDisposeelementuDisposableEffect. - niestatyczne klasy wewnętrzne, takie jak
Runnable, które mogą przechowywać 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 Pola i Odniesienia 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, należy 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 pozostawienie jej uruchomionej przez jakiś czas przed sprawdzeniem sterty. Wycieki mogą się przedostawać na górę alokacji na stercie. Jednak im mniejszy wyciek, tym dłużej musisz uruchamiać aplikację, aby go zobaczyć.
Możesz też wywołać wyciek pamięci na jeden z tych sposobów:
- Obróć urządzenie z orientacji pionowej do poziomej i z powrotem kilka razy, gdy jest w różnych stanach aktywności. Obrócenie urządzenia może często spowodować, że aplikacja wycieknie
Activity(a w konsekwencji hostowane drzewo interfejsu Compose i powiązane drzewa stanów), jeśli aplikacja przechowuje odwołanie doActivitylubContextw operacjach asynchronicznych lub zmiennych stanu. - Przełączaj się między swoją aplikacją a inną aplikacją w różnych stanach aktywności. Możesz na przykład przejść do ekranu głównego, a potem wrócić do aplikacji.
Eksportowanie i importowanie nagrania zrzutu stosu
Możesz wyeksportować i zaimportować plik zrzutu stosu z karty Wcześniejsze nagrania w profilerze. Android Studio zapisuje nagranie jako plik .hprof.
Jeśli chcesz użyć innego analizatora plików .hprof, takiego jak jhat, musisz przekonwertować plik .hprof z formatu Androida na format pliku .hprof Java SE. Aby przekonwertować format pliku, użyj narzędzia hprof-conv dostępnego 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, wraz z nową nazwą pliku .hprof. Przykład:
hprof-conv heap-original.hprof heap-converted.hprof