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:
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.
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 Activity i Fragment 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
ActivitylubContext, które mogą ujawniać wykres kompozycji Compose hostowanej (np.ComposeViewi 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
onDisposefunkcjiDisposableEffect. - 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 Pola i Odwoł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
ActivitylubContextw 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