The Memory Profiler jest komponentem wAndroid Profiler, który pomaga zidentyfikować wycieki pamięci i pamięci churn, które mogą prowadzić do stutter, zamrożenia, a nawet awarii aplikacji. Pokazuje on w czasie rzeczywistym wykres wykorzystania pamięci przez Twoją aplikację i pozwala przechwycić zrzut sterty, wymusić zbieranie śmieci i śledzić alokacje pamięci.
Aby otworzyć Profiler pamięci, wykonaj następujące kroki:
- Kliknij Widok > Okna narzędziowe > Profiler (możesz również kliknąć Profil na pasku narzędzi).
- Wybierz urządzenie i proces aplikacji, który chcesz profilować z paska narzędzi AndroidProfiler. Jeśli podłączyłeś urządzenie przez USB, ale nie widzisz go na liście, upewnij się, że masz włączone debugowanie USB.
- Kliknij dowolne miejsce na osi czasu MEMORY, aby otworzyć Memory Profiler.
Alternatywnie, możesz sprawdzić pamięć aplikacji z wiersza poleceń za pomocądumpsys, a także zobaczyć zdarzenia GC w logcat.
Dlaczego powinieneś profilować pamięć swojej aplikacji
Android zapewnia zarządzane środowisko pamięci – gdy stwierdzi, że twoja aplikacja nie używa już niektórych obiektów, garbage collector zwalnia nieużywaną pamięć z powrotem do sterty. To, jak Android radzi sobie z wyszukiwaniem niewykorzystanej pamięci, jest ciągle ulepszane, ale w pewnym momencie na wszystkich wersjach Androida system musi na krótko wstrzymać Twój kod. Przez większość czasu, te pauzy są niezauważalne. Jednakże, jeśli twoja aplikacja alokuje pamięć szybciej niż system może ją zebrać, twoja aplikacja może być opóźniona, podczas gdy kolektor zwalnia wystarczająco dużo pamięci, aby zaspokoić swoje alokacje. Opóźnienie to może spowodować, że twoja aplikacja będzie pomijać ramki i powodować widoczne spowolnienie.
Nawet jeśli twoja aplikacja nie wykazuje spowolnienia, jeśli wycieka pamięć, może zachować tę pamięć, nawet gdy jest w tle. To zachowanie może spowolnić resztę systemu wydajność pamięci przez wymuszanie niepotrzebnych zdarzeń garbage collectionevents. W końcu system jest zmuszony do zabicia procesu Twojej aplikacji, aby odzyskać pamięć. Następnie, gdy użytkownik powróci do aplikacji, musi się ona całkowicie zrestartować.
Aby zapobiec tym problemom, należy użyć narzędzia Memory Profiler do wykonania następujących czynności:
- Poszukaj niepożądanych wzorców alokacji pamięci na osi czasu, które mogą powodować problemy z wydajnością.
- Zrzuty sterty Java, aby zobaczyć, które obiekty zużywają pamięć w danym momencie. Kilka zrzutów sterty w dłuższym okresie czasu może pomóc w identyfikacji wycieków pamięci.
- Rejestruj alokacje pamięci podczas normalnej i ekstremalnej interakcji z użytkownikiem, aby dokładnie określić, gdzie Twój kod alokuje zbyt wiele obiektów w krótkim czasie lub alokuje obiekty, które stają się nieszczelne.
W celu uzyskania informacji o praktykach programistycznych, które mogą zmniejszyć zużycie pamięci przez Twoją aplikację, przeczytaj Zarządzanie pamięcią aplikacji.
Przegląd narzędzia Memory Profiler
Po pierwszym otwarciu narzędzia Memory Profiler zobaczysz szczegółową oś czasu użycia pamięci przez Twoją aplikację i uzyskasz dostęp do narzędzi wymuszających zbieranie śmieci, przechwytywanie zrzutu sterty i rejestrowanie alokacji pamięci.
Figura 1. Memory Profiler
Jak pokazano na rysunku 1, domyślny widok Memory Profiler zawiera następujące elementy:
- Przycisk do wymuszenia zdarzenia garbage collection.
-
Przycisk do przechwycenia zrzutu sterty.
Uwaga: Przycisk do rejestrowania alokacji pamięci pojawia się na prawo od przycisku zrzutu sterty tylko wtedy, gdy jest podłączony do urządzenia z systemem Android 7.1 (poziom API 25) lub niższym.
- Menu rozwijane pozwalające określić, jak często profiler przechwytuje alokacje pamięci. Wybór odpowiedniej opcji może pomóc poprawić wydajność aplikacji podczas profilowania.
- Przyciski do powiększania/pomniejszania osi czasu.
- Przycisk do przeskakiwania do przodu do danych pamięci na żywo.
- Osiem zdarzeń, który pokazuje stany aktywności, zdarzenia wejścia użytkownika i zdarzenia obrotu ekranu.
- Okres czasowy użycia pamięci, który zawiera następujące elementy:
- Wykres w postaci stosu przedstawiający ilość pamięci używanej przez każdą kategorię pamięci, zgodnie z osią y po lewej stronie i kluczem kolorów u góry.
- Linia przerywana wskazuje liczbę zaalokowanych obiektów, jak wskazuje oś y po prawej stronie.
- Ikona dla każdego zdarzenia zbierania śmieci.
Jednakże, jeśli używasz urządzenia z systemem Android 7.1 lub niższym, nie wszystkie dane profilowania są domyślnie widoczne. Jeśli zobaczysz komunikat z napisem „Zaawansowane profilowanie jest niedostępne dla wybranego procesu”, musisz włączyć zaawansowane profilowanie, aby zobaczyć następujące dane:
- Oś czasu zdarzeń
- Liczba zaalokowanych obiektów
- Zdarzenia zbierania śmieci
W systemie Android 8.0 i wyższych, zaawansowane profilowanie jest zawsze włączone dla debuggableapps.
Jak pamięć jest liczona
Liczby, które widzisz na górze Memory Profiler (rysunek 2) są oparte na wszystkich prywatnych stronach pamięci, które twoja aplikacja popełniła, zgodnie z systemem Androida. Ta liczba nie obejmuje stron współdzielonych z systemem innych aplikacji.
Figura 2. Legenda zliczania pamięci na górze Memory Profiler
Kategorie w zliczaniu pamięci są następujące:
- Java: Pamięć pochodząca z obiektów przydzielonych z kodu Java lub Kotlin.
-
Native: Pamięć pochodząca z obiektów alokowanych z kodu C lub C++.
Nawet jeśli nie używasz C++ w swojej aplikacji, możesz zobaczyć tu trochę pamięci natywnej, ponieważ framework Androida używa pamięci natywnej do obsługi różnych zadań w twoim imieniu, takich jak obsługa zasobów obrazu i innych grafik – nawet jeśli kod, który napisałeś, jest w Javie lub Kotlinie.
-
Grafika: Pamięć używana dla kolejek buforów graficznych do wyświetlania pikseli na ekranie, w tym powierzchni GL, tekstur GL i tak dalej. (Zauważ, że jest to pamięć współdzielona z CPU, a nie dedykowana pamięć GPU.)
-
Stos: Pamięć używana przez stosy natywne i stosy Java w twojej aplikacji. Zwykle odnosi się to do liczby wątków uruchomionych w aplikacji.
-
Kod: Pamięć, której aplikacja używa dla kodu i zasobów, takich jak kod bajtowy dex, zoptymalizowany lub skompilowany kod dex, biblioteki .so i czcionki.
-
Inne: Pamięć używana przez aplikację, której system nie jest pewien, jak sklasyfikować.
-
Allocated: Liczba obiektów Java/Kotlin zaalokowanych przez twoją aplikację. To nie liczy obiektów przydzielonych w C lub C++.
Po podłączeniu do urządzenia z systemem Android 7.1 i niższym, to liczenie alokacji rozpoczyna się tylko w momencie, gdy Memory Profiler połączył się z uruchomioną aplikacją. Tak więc wszelkie obiekty przydzielone przed rozpoczęciem profilowania nie są brane pod uwagę. Jednakże, Android 8.0 i nowszy zawiera narzędzie profilowania na urządzeniu, które śledzi wszystkie alokacje, więc ta liczba zawsze reprezentuje całkowitą liczbę obiektów Java pozostających w Twojej aplikacji na Androidzie 8.0 i nowszym.
W porównaniu do liczenia pamięci z poprzedniego narzędzia Monitor Androida, nowy Profiler Pamięci rejestruje pamięć inaczej, więc może się wydawać, że Twoje użycie pamięci jest teraz wyższe. Memory Profiler monitoruje kilka dodatkowych kategorii, które zwiększają sumę, ale jeśli zależy ci tylko na pamięci sterty Java, to liczba „Java” powinna być podobna do wartości z poprzedniego narzędzia.Chociaż liczba Java prawdopodobnie nie jest dokładnie zgodna z tym, co widziałeś w AndroidMonitor, nowa liczba uwzględnia wszystkie strony pamięci fizycznej, które zostały przydzielone do sterty Java aplikacji od czasu jej rozwidlenia z Zygote. Zapewnia to dokładną reprezentację tego, ile pamięci fizycznej faktycznie używa twoja aplikacja.
Zobacz alokacje pamięci
Alokacje pamięci pokazują, jak każdy obiekt Java i referencja JNI w twojej pamięci zostały przydzielone. W szczególności, Memory Profiler może pokazać następujące rzeczy na temat alokacji obiektów:
- Jakie typy obiektów zostały przydzielone i ile miejsca zajmują.
- Ślad stosu każdej alokacji, w tym w którym wątku.
- Kiedy obiekty zostały usunięte (tylko w przypadku korzystania z urządzenia z systemem Android 8.0 lub nowszym).
Jeśli urządzenie działa w systemie Android 8.0 lub nowszym, można wyświetlić alokacje obiektów w dowolnym momencie w następujący sposób: Przeciągnij na osi czasu, aby wybrać region, dla którego chcesz wyświetlić alokacje (jak pokazano na filmie 1). Nie ma potrzeby rozpoczynania sesji nagrywania, ponieważ Android 8.0 i nowsze wersje zawierają narzędzie profilowania, które stale śledzi alokacje Twojej aplikacji.
Wideo 1. W systemie Android 8.0 i nowszym wybierz istniejący obszar osi czasu, aby wyświetlić alokacje obiektów
Jeśli urządzenie działa w systemie Android 7.1 lub nowszym, kliknij przycisk Nagraj alokacje pamięci na pasku narzędzi Memory Profiler. Podczas nagrywania Profiler pamięci śledzi wszystkie alokacje, które występują w aplikacji. Gdy skończysz, kliknij przycisk Zatrzymaj nagrywanie (ten sam przycisk; zobacz wideo 2), aby wyświetlić alokacje.
Wideo 2. W systemie Android 7.1 i niższych należy jawnie rejestrować alokacje pamięci
Po wybraniu regionu osi czasu (lub po zakończeniu sesji nagrywania w urządzeniu z systemem Android 7.1 lub niżej), lista alokowanych obiektów pojawia się poniżej osi czasu, pogrupowana według nazwy klasy i posortowana według liczby sterty.
Aby sprawdzić zapis alokacji, wykonaj następujące kroki:
- Przeglądaj listę, aby znaleźć obiekty, które mają nietypowo dużą liczbę sterty i mogą być narażone na wyciek. Aby ułatwić znalezienie znanych klas, kliknij nagłówek kolumny Nazwa klasy, aby posortować ją alfabetycznie. Następnie kliknąć nazwę klasy. Po prawej stronie pojawi się panel Widok instancji, pokazujący każdą instancję tej klasy, jak pokazano na rysunku 3.
- Alternatywnie można szybko zlokalizować obiekty, klikając przycisk Filtruj lub naciskając Control+F (Command+F na Macu) i wpisując nazwę klasy lub pakietu w polu wyszukiwania. Możesz również wyszukiwać według nazwy metody, jeśli wybierzesz z menu rozwijanego opcjęArrange by callstack. Jeśli chcesz używać wyrażeń regularnych, zaznacz pole obok Regex. Zaznacz pole obok opcjiZapamiętaj wielkość liter, jeśli w wyszukiwaniu uwzględniana jest wielkość liter.
- W okienku Widok instancji kliknij instancję. Poniżej pojawia się karta Stos wywołań, pokazująca, gdzie ta instancja została przydzielona i w którym wątku.
- Na karcie Stos wywołań kliknij prawym przyciskiem myszy dowolny wiersz i wybierzSkocz do źródła, aby otworzyć ten kod w edytorze.
Rysunek 3. Szczegóły dotyczące każdego przydzielonego obiektu pojawiają się w widoku instancji po prawej stronie
Możesz użyć dwóch menu nad listą przydzielonych obiektów, aby wybrać stertę do sprawdzenia i sposób organizacji danych.
Z menu po lewej stronie wybierz stertę do sprawdzenia:
- sterta domyślna: Gdy żadna sterta nie jest określona przez system.
- sterta obrazu: Obraz startowy systemu, zawierający klasy, które są ładowane podczas startu systemu. Alokacje tutaj są gwarantowane, aby nigdy się nie poruszyć lub odejść.
- sterta zygoty: Sterta copy-on-write, z której rozwidla się proces aplikacji w systemie Android.
- app heap: Podstawowa sterta, na której twoja aplikacja alokuje pamięć.
- sterta JNI: Sterta, która pokazuje, gdzie są alokowane i zwalniane referencje Java Native Interface (JNI).
Z menu po prawej stronie wybierz, jak ułożyć alokacje:
- Ułóż według klasy: Grupuje wszystkie przydziały na podstawie nazwy klasy. Jest to ustawienie domyślne.
- Układaj według pakietów: Grupuje wszystkie alokacje na podstawie nazwy pakietu.
- Arrange by callstack: Grupuje wszystkie alokacje w odpowiadające im stosy wywołań.
Poprawa wydajności aplikacji podczas profilowania
Aby poprawić wydajność aplikacji podczas profilowania, profiler pamięci domyślnie okresowo próbkuje alokacje pamięci. Podczas testowania na urządzeniach z APIlevel 26 lub wyższym można zmienić to zachowanie, korzystając z listy rozwijanej Śledzenie alokacji. Dostępne opcje są następujące:
- Full: Przechwytuje wszystkie alokacje obiektów w pamięci. Jest to domyślne zachowanie w Android Studio 3.2 i wcześniejszych. Jeśli masz aplikację, która alokuje dużo obiektów, możesz zaobserwować widoczne spowolnienia podczas profilowania.
- Próbkowany: Próbkuje alokacje obiektów w pamięci w regularnych odstępach czasu. Jest to opcja domyślna i ma mniejszy wpływ na wydajność aplikacji podczas profilowania. Aplikacje, które alokują wiele obiektów w krótkim czasie, mogą nadal wykazywać widoczne spowolnienia.
- Wyłączone: Zatrzymuje śledzenie alokacji pamięci aplikacji.
Zobacz globalne referencje JNI
Java Native Interface (JNI) to framework, który pozwala kodowi Java i kodowi natywnemu na wzajemne wywoływanie się.
Oferty JNI są zarządzane ręcznie przez kod natywny, więc możliwe jest, że obiekty Java używane przez kod natywny będą utrzymywane przy życiu zbyt długo. Niektóre obiekty na stercie Javy mogą stać się nieosiągalne, jeśli referencja JNI zostanie odrzucona bez uprzedniego jawnego usunięcia. Możliwe jest również wyczerpanie globalnego limitu referencji JNI.
Aby rozwiązać takie problemy, użyj widoku sterty JNI w Memory Profiler, aby przejrzeć wszystkie globalne referencje JNI i przefiltrować je według typów Java i natywnych stosów wywołań. Dzięki tym informacjom można dowiedzieć się, kiedy i gdzie globalne referencje JNI są tworzone i usuwane.
Podczas działania aplikacji zaznacz fragment osi czasu, który chcesz zbadać, i wybierz stertę JNI z menu rozwijanego nad listą klas.Można wtedy przeglądać obiekty w stercie, tak jak normalnie, i dwukrotnie kliknąć obiekty w zakładce Stos wywołań alokacji, aby zobaczyć, gdzie referencje JNI są przydzielane i zwalniane w kodzie, jak pokazano na rysunku 4.
Rysunek 4. Wyświetlanie globalnych referencji JNI
Aby sprawdzić alokacje pamięci w kodzie JNI Twojej aplikacji, musisz wdrożyć aplikację na urządzenie z systemem Android 8.0 lub nowszym.
Więcej informacji na temat JNI można znaleźć w temacie Wskazówki dotyczące JNI.
Natywny profiler pamięci
Profiler pamięci Android Studio zawiera Natywny profiler pamięci dla aplikacji wdrażanych na urządzeniach fizycznych z systemem Android 10; wsparcie dla urządzeń z systemem Android 11 jest obecnie dostępne w wydaniu podglądu Android Studio 4.2.
Natywny profiler pamięci śledzi alokacje/dealokacje obiektów w kodzie natywnym przez określony czas i dostarcza następujących informacji:
- Alokacje: Liczba obiektów alokowanych za pomocą
malloc()
lub operatoranew
w wybranym okresie czasu. - Deallocations: Zliczanie obiektów deallokowanych za pośrednictwem
free()
lub operatoradelete
w wybranym okresie czasu. - Allocations Size: Zagregowany rozmiar w bajtach wszystkich alokacji w wybranym okresie czasu.
- Deallocations Size: Zagregowany rozmiar w bajtach wszystkich zwolnień pamięci w wybranym okresie czasu.
- Total Count: Wartość w kolumnie Allocations minus wartość w kolumnie Deallocations.
- Pozostały rozmiar: Wartość w kolumnie Allocations Size minus wartość w kolumnie Deallocations Size.
Aby zainicjować nagrywanie, kliknij przycisk Record native allocations w górnej części oknaMemory Profiler:
Gdy będziesz gotowy do zakończenia nagrywania, kliknij przycisk Stop recording.
Domyślnie program Native Memory Profiler używa rozmiaru próbki 32 bajtów: Za każdym razem, gdy przydzielane są 32 bajty pamięci, wykonywana jest migawka pamięci. Mniejszy rozmiar próbki powoduje częstsze wykonywanie zrzutów, dając bardziej dokładne dane o wykorzystaniu pamięci. Większy rozmiar próbki daje mniej dokładne dane, ale zużywa mniej zasobów w systemie i poprawia wydajność podczas nagrywania.
Aby zmienić rozmiar próbki Native Memory Profiler:
- Wybierz Run > Edit Configurations.
- Wybierz moduł aplikacji w lewym panelu.
- Kliknij kartę Profilowanie i wprowadź rozmiar próbki w polu oznaczonym Interwał próbkowania pamięci natywnej (bajty).
- Zbuduj i uruchom ponownie swoją aplikację.
Zrzut sterty
Zrzut sterty pokazuje, które obiekty w twojej aplikacji używają pamięci w czasie, gdy przechwytujesz zrzut sterty. Zwłaszcza po dłuższej sesji użytkownika, zrzut sterty może pomóc zidentyfikować wycieki pamięci, pokazując obiekty nadal w pamięci, które twoim zdaniem nie powinny się tam już znajdować.
Po przechwyceniu zrzutu sterty możesz zobaczyć następujące rzeczy:
- Jakie typy obiektów zaalokowała twoja aplikacja i ile każdego z nich.
- Ile pamięci używa każdy obiekt.
- Gdzie w twoim kodzie są przechowywane odwołania do każdego obiektu.
- Stos wywołań dla miejsca, w którym obiekt został przydzielony. (Stosy połączeń są obecnie dostępne z zrzutem sterty tylko w systemie Android 7.1 i niższych, gdy przechwytujesz zrzut sterty podczas rejestrowania alokacji.)
Aby przechwycić zrzut sterty, kliknij Zrzut sterty Java na pasku narzędzi Memory Profiler.Podczas zrzucania sterty, ilość pamięci Java może tymczasowo wzrosnąć.Jest to normalne, ponieważ zrzut sterty odbywa się w tym samym procesie co aplikacja i wymaga trochę pamięci do zebrania danych.
Zrzut sterty pojawia się poniżej osi czasu pamięci, pokazując wszystkie typy klas w stercie, jak pokazano na rysunku 5.
Rysunek 5. Przeglądanie zrzutu sterty
Jeśli potrzebujesz bardziej precyzyjnego określenia momentu utworzenia zrzutu, możesz utworzyć zrzut sterty w krytycznym punkcie kodu aplikacji, wywołującdumpHprofData()
.
Na liście klas możesz zobaczyć następujące informacje:
- Alokacje: Liczba alokacji w stercie.
-
Rozmiar natywny: Całkowita ilość pamięci natywnej używanej przez ten typ obiektu (w bajtach). Ta kolumna jest widoczna tylko dla Androida 7.0 i wyższych.
Zobaczysz tutaj pamięć dla niektórych obiektów przydzielonych w Javie, ponieważ Android używa natywnej pamięci dla niektórych klas frameworka, takich jak
Bitmap
. -
Rozmiar płytki: Całkowita ilość pamięci Java używanej przez ten typ obiektu (w bajtach).
-
Retained Size: Total size of memory being retained due to all instancesof this class (in bytes).
Możesz użyć dwóch menu nad listą przydzielonych obiektów, aby wybrać, które zrzuty sterty mają zostać zbadane i jak zorganizować dane.
Z menu po lewej stronie wybierz, która sterta ma zostać zbadana:
- sterta domyślna: Gdy żadna sterta nie jest określona przez system.
- sterta aplikacji: Podstawowa sterta, na której twoja aplikacja alokuje pamięć.
- sterta obrazu: Obraz startowy systemu, zawierający klasy, które są ładowane podczas startu systemu. Przydziały tutaj są gwarantowane, że nigdy się nie przeniosą ani nie znikną.
- sterta zygoty: Sterta copy-on-write, z której rozwidla się proces aplikacji w systemie Android.
Z menu po prawej stronie wybierz, jak ułożyć alokacje:
- Arrange by class: Grupuje wszystkie przydziały na podstawie nazwy klasy. Jest to ustawienie domyślne.
- Układaj według pakietów: Grupuje wszystkie alokacje na podstawie nazwy pakietu.
- Arrange by callstack: Grupuje wszystkie alokacje w odpowiadające im stosy wywołań. Ta opcja działa tylko wtedy, gdy przechwytujesz zrzut sterty podczas rejestrowania alokacji. Nawet jeśli tak się stanie, prawdopodobnie na stercie znajdują się obiekty, które zostały zaalokowane przed rozpoczęciem nagrywania, więc te alokacje pojawiają się jako pierwsze, po prostu wymienione według nazwy klasy.
Lista jest domyślnie posortowana według kolumny Retained Size. Aby posortować według wartości w innej kolumnie, kliknąć nagłówek kolumny.
Kliknąć nazwę klasy, aby otworzyć okno Widok instancji po prawej stronie (pokazane na rys. 6). Każda wymieniona instancja zawiera następujące informacje:
- Depth: Najkrótsza liczba hopsów od dowolnego korzenia GC do wybranej instancji.
- Native Size: Rozmiar tej instancji w pamięci natywnej.Ta kolumna jest widoczna tylko dla systemu Android 7.0 i nowszych.
- Shallow Size: Rozmiar tej instancji w pamięci Java.
- Retained Size: Rozmiar pamięci, którą ta instancja dominuje (zgodnie z drzewem dominatorów).
Rysunek 6. Czas potrzebny do przechwycenia zrzutu sterty jest pokazany na osi czasu
Aby sprawdzić stertę, wykonaj następujące kroki:
- Przeglądaj listę, aby znaleźć obiekty, które mają nietypowo dużą ilość sterty i mogą być nieszczelne. Aby ułatwić znalezienie znanych klas, kliknij nagłówek kolumny Nazwa klasy, aby posortować ją alfabetycznie. Następnie kliknąć nazwę klasy. Po prawej stronie pojawi się panel Widok instancji, pokazujący każdą instancję tej klasy, jak pokazano na rysunku 6.
- Alternatywnie można szybko zlokalizować obiekty, klikając przycisk Filtrujlub naciskając Control+F (Command+F na Macu) i wpisując nazwę klasy lub pakietu w polu wyszukiwania. Możesz również wyszukiwać według nazwy metody, jeśli wybierzesz z menu rozwijanego opcjęArrange by callstack. Jeśli chcesz używać wyrażeń regularnych, zaznacz pole obok Regex. Zaznacz pole obokMatch case, jeśli w zapytaniu ma być uwzględniana wielkość liter.
- W okienku Widok instancji kliknij instancję. Możesz również kliknąć strzałkę obok nazwy instancji, aby wyświetlić wszystkie jej pola, a następnie kliknąć nazwę pola, aby wyświetlić wszystkie jego referencje. Jeśli chcesz wyświetlić szczegóły instancji dla pola, kliknij prawym przyciskiem myszy na pole i wybierz polecenie Przejdź do instancji.
- W zakładce Referencje, jeśli zidentyfikujesz referencję, która może tracić pamięć, kliknij ją prawym przyciskiem myszy i wybierz polecenie Przejdź do instancji. Spowoduje to wybranie odpowiedniej instancji ze sterty, pokazując jej dane.
W stercie szukaj wycieków pamięci spowodowanych przez następujące elementy:
- Długotrwałe odniesienia do
Activity
,Context
,View
,Drawable
i innych obiektów, które mogą zawierać odniesienia do konteneraActivity
lubContext
. - Niestatyczne klasy wewnętrzne, takie jak
Runnable
, które mogą przechowywać instancjęActivity
. - Cache, które przechowują obiekty dłużej niż to konieczne.
Zapisywanie zrzutu sterty jako pliku HPROF
Po przechwyceniu zrzutu sterty dane są widoczne w programie Memory Profiler tylko w czasie działania profilera. Kiedy kończysz sesję profilowania, tracisz zrzut sterty. Tak więc, jeśli chcesz zachować go do wglądu później, wyeksportuj zrzut sterty do pliku HPROF. W Android Studio 3.1 i niższych, przycisk Export capture to file znajduje się po lewej stronie paska narzędzi poniżej osi czasu; w Android Studio 3.2 i wyższych, jest przycisk Export Heap Dump na prawo od każdego wpisu Heap Dump w panelu Sessions. W wyświetlonym oknie dialogowym Export As zapisz plik z rozszerzeniem nazwy pliku .hprof
.
Aby użyć innego analizatora HPROF, takiego jakejhat, musisz przekonwertować plik HPROF z formatu Androida na format Java SE HPROF. Możesz to zrobić za pomocą narzędzia hprof-conv
znajdującego się w kataloguandroid_sdk/platform-tools/
. Uruchom polecenie hprof-conv
z dwoma argumentami: oryginalnym plikiem HPROF i lokalizacją do zapisu przekonwertowanego pliku HPROF. Na przykład:
hprof-conv heap-original.hprof heap-converted.hprof
Import a heap dump file
Aby zaimportować plik HPROF (.hprof
), kliknij przycisk Start a new profiling session w paneluSessions, wybierz opcję Load from file i wybierz plik z przeglądarki plików.
Możesz również zaimportować plik HPROF, przeciągając go z przeglądarki plików do okna edytora.
Wykrywanie wycieków w Profilerze pamięci
Podczas analizowania zrzutu sterty w Profilerze pamięci można filtrować dane profilowania, które zdaniem Android Studio mogą wskazywać na wycieki pamięci dla Activity
iFragment
instancji w aplikacji.
Typy danych, które pokazuje filtr, obejmują następujące elementy:
-
Activity
instancje, które zostały zniszczone, ale nadal są przywoływane. -
Fragment
instancje, które nie mają ważnegoFragmentManager
, ale nadal są przywoływane.
W niektórych sytuacjach, takich jak poniższe, filtr może dawać fałszywe wyniki:
- A
Fragment
jest tworzony, ale nie został jeszcze użyty. - A
Fragment
jest buforowany, ale nie jako częśćFragmentTransaction
.
Aby użyć tej funkcji, najpierw przechwyć zrzut sterty lub zaimportuj plik zrzutu sterty do programu Android Studio. Aby wyświetlić fragmenty i aktywności, które mogą wyciekać z pamięci, należy zaznaczyć pole wyboru Activity/Fragment Leaks w panelu heapdump Profiler Memory, jak pokazano na rysunku 7.
Figura 7. Filtrowanie zrzutu sterty w poszukiwaniu wycieków pamięci.
Techniki profilowania pamięci
Podczas korzystania z Memory Profiler należy zestresować kod aplikacji i spróbować znaleźć wycieki pamięci. Jednym ze sposobów na sprowokowanie wycieków pamięci w twojej aplikacji jest pozwolenie jej działać przez jakiś czas przed sprawdzeniem sterty. Przecieki mogą podciekać do góry alokacji na stercie. Jednakże, im mniejszy wyciek, tym dłużej trzeba uruchomić aplikację, aby go zobaczyć.
Możesz również wywołać wyciek pamięci w jeden z następujących sposobów:
- Obróć urządzenie z pozycji pionowej do poziomej i z powrotem wiele razy, podczas gdy w różnych stanach aktywności. Obracanie urządzenia może często powodować wyciek obiektów
Activity
,Context
lubView
, ponieważ system tworzy obiektActivity
i jeśli aplikacja posiada odniesienie do jednego z tych obiektów gdzieś indziej, system nie może go odśmiecić. - Przełączaj się między swoją aplikacją a inną aplikacją, będąc w różnych stanach aktywności (przejdź do ekranuHome, a następnie wróć do swojej aplikacji).
Porada: Możesz również wykonać powyższe kroki, używając themonkeyrunner testframework.