Sprawdzanie wykorzystania pamięci przez aplikację za pomocą narzędzia Memory Profiler

Program profilujący pamięci to komponent programu profilującego Androida, który pomaga wykrywać wycieki pamięci i ich rezygnacje, które mogą prowadzić do zacinania się, zawieszania się, a nawet awarii aplikacji. Wyświetla wykres w czasie rzeczywistym wykorzystania pamięci przez aplikację i pozwala przechwytywać zrzut stosu, wymuszać czyszczenie pamięci i śledzić przydziały pamięci.

Aby otworzyć narzędzie Memory Profiler, wykonaj te czynności:

  1. Kliknij Widok > Okna narzędzi > Profiler (możesz też kliknąć Profil na pasku narzędzi).
  2. Na pasku narzędzi Android Profileer wybierz urządzenie i proces aplikacji, które chcesz profilować. Jeśli po podłączeniu urządzenia przez USB nie widzisz go na liście, sprawdź, czy debugowanie USB jest włączone.
  3. Kliknij dowolne miejsce na osi czasu MEMORY, aby otworzyć narzędzie Memory Profiler.

Pamięć aplikacji możesz też sprawdzić z poziomu wiersza poleceń za pomocą dumpsys i wyświetlić zdarzenia GC w narzędziu Logcat.

Dlaczego warto profilować pamięć aplikacji

Android zapewnia środowisko zarządzanej pamięci – gdy ustali, że aplikacja nie korzysta już z niektórych obiektów, kolektor śmieci wypuszcza nieużywaną pamięć z powrotem na stos. Cały czas ulepszamy sposób znajdowania nieużywanej pamięci na Androidzie, ale w pewnym momencie w przypadku wszystkich wersji 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ą zebrać, aplikacja może zostać opóźniona, gdy kolektor zwolni wystarczająco dużo pamięci, aby zrealizować przydziały. Opóźnienie może spowodować, że aplikacja pominie klatki i będzie spowalniać aplikację.

Nawet jeśli aplikacja nie wykazuje powolnego działania, jeśli wycieknie z pamięci, może ją zachować nawet wtedy, gdy działa w tle. Takie zachowanie może spowolnić pozostałą część pamięci systemu, wymuszając niepotrzebne zdarzenia czyszczenia pamięci. W końcu system będzie zmuszony zamknąć proces aplikacji, aby odzyskać pamięć. Następnie, gdy użytkownik wróci do aplikacji, musi ona zostać całkowicie uruchomiona ponownie.

Aby zapobiec tym problemom, należy użyć narzędzia Memory Profiler do następujących zadań:

  • Poszukaj na osi czasu niepożądanych wzorców alokacji pamięci, które mogą powodować problemy z wydajnością.
  • Zrzuć stertę Javy, aby sprawdzić, które obiekty wykorzystują pamięć w danym czasie. Kilka zrzutów stosu w dłuższym okresie może ułatwić rozpoznanie wycieków pamięci.
  • Rejestruj przydziały pamięci podczas normalnej i ekstremalnej interakcji użytkownika, aby dokładnie określić, w którym miejscu kod przydziela w krótkim czasie zbyt wiele obiektów lub obiekty, które uległy wyciekowi.

Informacje o praktykach programowania, które mogą zmniejszyć wykorzystanie pamięci przez aplikację, znajdziesz w artykule Zarządzanie pamięcią aplikacji.

Omówienie programu profilującego pamięć

Po pierwszym uruchomieniu programu do profilowania pamięci zobaczysz szczegółową oś czasu wykorzystania pamięci przez aplikację oraz uzyskasz dostęp do narzędzi pozwalających wymuszać czyszczenie pamięci, rejestrować zrzut stosu i rejestrować przydziały pamięci.

Rysunek 1. Narzędzie do profilowania pamięci

Jak zaznaczono na ilustracji 1, domyślny widok narzędzia do profilowania pamięci obejmuje:

  1. Przycisk wymuszania zdarzenia czyszczenia pamięci.
  2. Przycisk do rejestrowania zrzutu stosu.

    Uwaga: przycisk rejestrowania przydziałów pamięci wyświetla się po prawej stronie przycisku zrzutu stosu tylko wtedy, gdy jest połączone z urządzeniem z Androidem 7.1 (poziom interfejsu API 25) lub niższym.

  3. Menu określające, jak często program profilujący przechwytuje alokacje pamięci. Wybór odpowiedniej opcji może pomóc zwiększyć wydajność aplikacji podczas profilowania.
  4. Przyciski powiększania i pomniejszania osi czasu.
  5. Przycisk, który umożliwia przejście do bieżących danych pamięci.
  6. Oś czasu zdarzenia, która pokazuje stany aktywności, zdarzenia wprowadzania danych przez użytkownika oraz zdarzenia obrotu ekranu.
  7. Oś czasu wykorzystania pamięci, która zawiera:
    • Skumulowany wykres wykorzystania pamięci przez poszczególne kategorie pamięci pokazany przez oś Y po lewej stronie i kolorowy klawisz u góry.
    • Linia przerywana wskazuje liczbę przydzielonych obiektów zgodnie z osią Y po prawej stronie.
    • Ikona każdego zdarzenia czyszczenia pamięci.

Jeśli jednak używasz urządzenia z Androidem 7.1 lub starszym, nie wszystkie dane profilowania są domyślnie widoczne. Jeśli pojawi się komunikat „Zaawansowane profilowanie jest niedostępne dla wybranego procesu”, musisz włączyć zaawansowane profilowanie, aby wyświetlić:

  • Oś czasu zdarzenia
  • Liczba przydzielonych obiektów
  • Wydarzenia dotyczące wywozu odpadów

W Androidzie 8.0 i nowszych profilowanie zaawansowane jest zawsze włączone dla aplikacji z możliwością debugowania.

Jak liczona jest pamięć

W zależności od systemu Android liczby wyświetlane u góry programu do profilowania pamięci (ilustracja 2) są oparte na wszystkich stronach pamięci prywatnej zatwierdzonej przez aplikację. Nie uwzględnia ona stron udostępnionych systemowi lub innym aplikacjom.

Rysunek 2. Legenda liczby pamięci u góry narzędzia Memory Profiler

Kategorie pamięci:

  • Java: pamięć z obiektów alokowanych z kodu Java lub Kotlin.
  • Natywna: pamięć pochodząca z obiektów alokowanych z kodu C lub C++.

    Nawet jeśli w swojej aplikacji nie używasz C++, możesz zauważyć tutaj używaną pamięć natywną, ponieważ platforma Androida używa pamięci natywnej do wykonywania różnych zadań w Twoim imieniu, takich jak obsługa zasobów graficznych i innych elementów graficznych – mimo że napisany przez Ciebie kod jest w języku Java lub Kotlin.

  • Grafika: pamięć używana do tworzenia kolejek bufora grafiki do wyświetlania pikseli na ekranie, w tym platform GL, tekstur GL itp. (Pamiętaj, że jest to pamięć współużytkowana przez procesor, a nie dedykowaną pamięć GPU).

  • Stos: pamięć używana przez stosy natywne i Java w aplikacji. Zwykle jest związana z liczbą uruchomionych wątków.

  • Kod: pamięć używana przez aplikację na potrzeby kodu i zasobów, np. kod bajtowy .dex, zoptymalizowany lub skompilowany kod dex, biblioteki .so i czcionki.

  • Inne: pamięć używana przez aplikację, której system nie jest w stanie sklasyfikować.

  • Przydzielono: liczba obiektów Java/Kotlin przydzielonych przez aplikację. Nie uwzględnia obiektów alokowanych w C lub C++.

    Po połączeniu z urządzeniem z Androidem 7.1 lub starszym ta liczba przydziałów jest liczona tylko wtedy, gdy program profilu pamięci połączy się z uruchomioną aplikacją. Dlatego obiekty przydzielone przed rozpoczęciem profilowania nie są uwzględniane. Android 8.0 i nowsze wersje zawierają jednak dostępne na urządzeniu narzędzie do profilowania, które śledzi wszystkie alokacje. Ta liczba zawsze reprezentuje łączną liczbę obiektów Java widocznych w Twojej aplikacji na Androida 8.0 i nowszych.

W porównaniu z liczbą pamięci z poprzedniego narzędzia Android Monitor to nowy program do profilowania pamięci inaczej rejestruje pamięć, więc może się wydawać, że jej wykorzystanie jest teraz większe. Narzędzie do profilowania pamięci monitoruje dodatkowe kategorie, które zwiększają łączną liczbę. Jeśli jednak interesuje Cię tylko pamięć sterty Java, wartość „Java” powinna być podobna do wartości z poprzedniego narzędzia. Chociaż numer Java prawdopodobnie nie jest dokładnie taki sam jak w Android Monitorze, nowa liczba uwzględnia wszystkie strony pamięci fizycznej, które zostały przydzielone do sterty Java aplikacji od rozwidlenia z Zygote. Daje to więc dokładny odzwierciedlenie ilości pamięci fizycznej tak naprawdę wykorzystywanej przez aplikację.

Wyświetl przydziały pamięci

Przydziały pamięci pokazują, jak zostały przydzielone poszczególne obiekty Java i odwołania JNI w pamięci. Program profilujący pamięci może wyświetlić następujące informacje na temat przydziałów obiektów:

  • Typy obiektów, które zostały przydzielone, oraz ile miejsca zajmują.
  • Zrzut stosu każdego alokacji, w tym w którym wątku.
  • Moment usunięcia przydziału obiektów (tylko w przypadku urządzeń z Androidem 8.0 lub nowszym).

Aby rejestrować przydziały w Javie i Kotlin, wybierz Zarejestruj przydziały Java / Kotlin, a potem Record. Jeśli urządzenie korzysta z Androida 8 lub nowszego, interfejs programu do profilowania pamięci wyświetli osobny ekran z trwającym nagraniem. Możesz korzystać z miniosi czasu nad nagraniem (na przykład aby zmienić zakres wyboru). Aby zakończyć nagrywanie, wybierz Zatrzymaj .

Wizualizacja alokacji Java w narzędziu Memory Profiler

W Androidzie 7.1 i starszych program do profilowania pamięci korzysta ze starszego rejestrowania alokacji, które wyświetla nagranie na osi czasu, dopóki nie klikniesz Zatrzymaj.

Gdy wybierzesz region na osi czasu (lub zakończysz sesję nagrywania na urządzeniu z Androidem 7.1 lub starszym), pojawi się lista przydzielonych obiektów, pogrupowane według nazwy klasy i posortowane według liczby sterty.

Aby sprawdzić rekord alokacji, wykonaj te czynności:

  1. Przejrzyj listę, aby znaleźć obiekty z wyjątkowo dużą liczbą sterty i które mogły wyciekły. Jeśli chcesz znaleźć znane klasy, kliknij nagłówek kolumny Nazwa klasy i posortować alfabetycznie. Następnie kliknij nazwę zajęć. Po prawej stronie pojawi się panel Widok instancji z wyszczególnionymi instancjami klasy, jak widać na ilustracji 3.
    • Możesz też szybko znaleźć obiekty, klikając Filtruj lub naciskając Control+F (Command+F na Macu) i wpisując nazwę klasy lub pakietu w polu wyszukiwania. Możesz też wyszukiwać według nazwy metody, jeśli z menu wybierzesz Rozmieść według stosu wywołań. Jeśli chcesz używać wyrażeń regularnych, zaznacz pole obok Wyrażenie regularne. Zaznacz pole Uwzględnij wielkość liter, jeśli w zapytaniu rozróżniana jest wielkość liter.
  2. W panelu Widok instancji kliknij instancję. Poniżej pojawi się karta Stos wywołań z informacjami o tym, gdzie instancja została przydzielona i w którym wątku.
  3. Na karcie Stos wywołań kliknij prawym przyciskiem myszy dowolny wiersz i wybierz Przejdź do źródła, by otworzyć kod w edytorze.

Rysunek 3. Szczegółowe informacje o każdym przydzielonych obiektach są wyświetlane w widoku instancji po prawej stronie.

Możesz korzystać z 2 menu nad listą przydzielonych obiektów, aby wybrać stertę do sprawdzenia i uporządkować dane.

W menu po lewej stronie wybierz stertę do sprawdzenia:

  • default sterta: gdy system nie określa sterty;
  • sterta obrazów: obraz rozruchowy systemu zawierający klasy, które są wstępnie wczytywane podczas rozruchu. Przydziały w tym miejscu na pewno nigdy nie przeniosą się ani nie znikną.
  • sterty zygote: sterta kopiowania przy zapisie, w której następuje rozwidlenie procesu aplikacji w systemie Androida.
  • sterta aplikacji: główna sterta, na której aplikacja przydziela pamięć.
  • Stosa JNI: sterta, która pokazuje, gdzie są przydzielane i zwalniane odwołania interfejsu Java Native Interface (JNI).

W menu po prawej stronie wybierz sposób rozmieszczenia przydziałów:

  • Rozmieść według klasy: grupuje wszystkie przydziały na podstawie nazwy klasy. Jest to ustawienie domyślne.
  • Rozmieść według pakietu: grupuje wszystkie przydziały na podstawie nazwy pakietu.
  • Rozmieść według stosu wywołań: grupuje wszystkie alokacje w odpowiadające im stosy wywołań.

Zwiększ wydajność aplikacji podczas profilowania

Aby poprawić wydajność aplikacji podczas profilowania, program do profilowania pamięci domyślnie okresowo próbkuje alokacje pamięci. Podczas testowania aplikacji na urządzeniach z interfejsem API na poziomie 26 lub wyższym możesz zmienić ten sposób działania, korzystając z menu Śledzenie przydziałów. Dostępne opcje:

  • Pełne: wszystkie przydziały obiektów w pamięci są rejestrowane. Jest to domyślne działanie w Android Studio 3.2 i starszych. Jeśli masz aplikację, która alokuje wiele obiektów, podczas profilowania możesz zauważyć widoczne spowolnienia działania.
  • Próbkowane: próbkuje przydziały obiektów w pamięci w regularnych odstępach czasu. Jest to opcja domyślna, która ma mniejszy wpływ na wydajność aplikacji podczas profilowania. W przypadku aplikacji, które w krótkim czasie przydzielają dużo obiektów, nadal mogą występować widoczne spowolnienia.
  • Wył.: zatrzymuje śledzenie przydziału pamięci przez aplikację.

Wyświetl odwołania do globalnych JNI

Interfejs Java Native Interface (JNI) to platforma, która umożliwia komunikowanie się między kodami w języku Java i kodem natywnym.

Odwołaniami JNI są zarządzane ręcznie przez kod natywny, więc obiekty Java używane przez kod natywny mogą być utrzymywane przez zbyt długi czas. Niektóre obiekty na stercie Java mogą stać się nieosiągalne, jeśli odwołanie do JNI zostanie odrzucone bez wcześniejszego usunięcia. Może się również wyczerpać globalny limit referencyjny JNI.

Aby rozwiązać takie problemy, użyj widoku sterty JNI w narzędziu Memory Profiler do przeglądania wszystkich globalnych odwołań do JNI i filtruj je według typów Javy i natywnych stosów wywołań. Dzięki tym informacjom możesz dowiedzieć się, kiedy i gdzie są tworzone i usuwane globalne odwołania JNI.

Gdy aplikacja jest uruchomiona, wybierz fragment osi czasu, który chcesz sprawdzić, i wybierz stertę JNI z menu nad listą zajęć. Możesz teraz w normalny sposób badać obiekty na stercie i kliknąć dwukrotnie obiekty na karcie Stos wywołań przydziału, aby zobaczyć, gdzie w kodzie są przydzielane i udostępniane odwołania do JNI, jak pokazano na rysunku 4.

Rysunek 4. Wyświetlanie odwołań do globalnych JNI

Aby sprawdzić przydziały pamięci dla kodu JNI aplikacji, musisz wdrożyć aplikację na urządzeniu z Androidem 8.0 lub nowszym.

Aby dowiedzieć się więcej o JNI, zobacz wskazówki dotyczące JNI.

Program profilujący pamięci natywnej

Narzędzie do profilowania pamięci w Android Studio zawiera narzędzie profilujące pamięć natywną na potrzeby aplikacji wdrażanych na fizycznych i wirtualnych urządzeniach z Androidem 10 lub nowszym.

Program do profilowania pamięci natywnej śledzi przydziały/delokacje obiektów w kodzie natywnym dla określonego przedziału czasu i udostępnia te informacje:

  • Przydziały: liczba obiektów alokowanych za pomocą operatora malloc() lub operatora new w wybranym okresie.
  • Deallocations:liczba obiektów przydzielonych za pomocą free() lub operatora delete w wybranym okresie.
  • Rozmiar przydziałów: łączny rozmiar wszystkich przydziałów w wybranym okresie (w bajtach).
  • Rozmiar transakcji: zagregowany rozmiar całej wolnej pamięci w wybranym okresie w bajtach.
  • Łączna liczba: wartość w kolumnie Allocations (Przydziały) pomniejszona o wartość w kolumnie Deallocations.
  • Pozostały rozmiar:wartość w kolumnie Allocations Size (Rozmiar przydziałów) pomniejszona o wartość w kolumnie Deallocations Rozmiar.

Program profilujący pamięci natywnej

Aby nagrywać przydziały natywne na urządzeniach z Androidem 10 lub nowszym, wybierz Rejestruj alokacje natywne, a potem kliknij Rejestruj. Nagrywanie jest kontynuowane, dopóki nie klikniesz Zatrzymaj . Interfejs narzędzia Memory Profiler przełączy się na osobny ekran z nagraniem natywnym.

Przycisk rejestrowania alokacji natywnych

W Androidzie 9 i starszych opcja Zarejestruj alokacje natywne jest niedostępna.

Domyślnie program profilujący pamięć natywny używa rozmiaru próbki 32 bajtów: za każdym razem, gdy przydzielone są 32 bajty pamięci, tworzony jest zrzut pamięci. Mniejszy rozmiar próbki oznacza częstsze tworzenie zrzutów, co zapewnia dokładniejsze dane o wykorzystaniu pamięci. Większa próbka zapewnia mniej dokładne dane, ale zużywa mniej zasobów systemu i zwiększa wydajność podczas rejestrowania.

Aby zmienić rozmiar próbki natywnego narzędzia do profilowania pamięci:

  1. Wybierz Uruchom > Edytuj konfiguracje.
  2. W panelu po lewej stronie wybierz moduł aplikacji.
  3. Kliknij kartę Profilowanie i wpisz rozmiar próbki w polu Interwał próbkowania pamięci natywnej (bajty).
  4. Skompiluj i uruchom aplikację ponownie.

Zrób zrzut stosu

Zrzut stosu pokazuje, które obiekty w aplikacji wykorzystują pamięć w momencie robienia zrzutu. Zwłaszcza po wydłużonej sesji użytkownika zrzut stosu może pomóc w identyfikacji wycieków pamięci, ponieważ pokazuje obiekty wciąż w pamięci, które Twoim zdaniem nie powinny już się tam znajdować.

Po przechwyceniu zrzutu stosu możesz wyświetlić te elementy:

  • typy obiektów przydzielonych przez aplikację i liczbę każdego z nich;
  • Ilość pamięci używanej przez każdy obiekt.
  • Gdzie w kodzie przechowywane są odwołania do poszczególnych obiektów.
  • Stos wywołań, do którego przydzielono obiekt. Stosy wywołań są obecnie dostępne ze zrzutem stosu tylko w Androidzie 7.1 i starszych, jeśli rejestrujesz zrzut stosu podczas rejestrowania alokacji.

Aby przechwycić zrzut stosu, kliknij Zarejestruj zrzut stosu, a następnie wybierz Nagraj. Podczas wykonywania zrzutu stosu ilość pamięci Java może się tymczasowo zwiększyć. Jest to normalne, ponieważ zrzut stosu odbywa się w tym samym procesie co aplikacja i wymaga nieco pamięci do zebrania danych.

Gdy program profilujący zakończy przechwytywanie zrzutu stosu, interfejs narzędzia do profilowania pamięci wyświetli się na osobnym ekranie, na którym będzie widoczny zrzut stosu.

Rysunek 5. Wyświetlam zrzut stosu.

Jeśli chcesz dokładniej określić, kiedy zrzut jest tworzony, możesz utworzyć zrzut stosu w krytycznym punkcie kodu aplikacji, wywołując funkcję dumpHprofData().

Na liście zajęć znajdziesz te informacje:

  • Przydziały: liczba przydziałów na stercie.
  • Rozmiar natywny: łączna ilość pamięci natywnej używanej przez ten typ obiektu (w bajtach). Ta kolumna jest widoczna tylko w Androidzie 7.0 i nowszych.

    Zobaczysz tutaj pamięć dla niektórych obiektów przydzielonych w Javie, ponieważ Android używa pamięci natywnej dla niektórych klas platformy, takich jak Bitmap.

  • Płytki rozmiar: łączna ilość pamięci Java używana przez ten typ obiektu (w bajtach).

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

Możesz korzystać z 2 menu nad listą przydzielonych obiektów, aby wybrać zrzuty sterty do sprawdzenia i sposób uporządkowania danych.

W menu po lewej stronie wybierz stertę do sprawdzenia:

  • default sterta: gdy system nie określa sterty;
  • sterta aplikacji: główna sterta, na której aplikacja przydziela pamięć.
  • sterta obrazów: obraz rozruchowy systemu zawierający klasy, które są wstępnie wczytywane podczas rozruchu. Przydziały w tym miejscu na pewno nigdy nie przeniosą się ani nie znikną.
  • sterty zygote: sterta kopiowania przy zapisie, w której następuje rozwidlenie procesu aplikacji w systemie Androida.

W menu po prawej stronie wybierz sposób rozmieszczenia przydziałów:

  • Rozmieść według klasy: grupuje wszystkie przydziały na podstawie nazwy klasy. Jest to ustawienie domyślne.
  • Rozmieść według pakietu: grupuje wszystkie przydziały na podstawie nazwy pakietu.
  • Rozmieść według stosu wywołań: grupuje wszystkie alokacje w odpowiadające im stosy wywołań. Ta opcja działa tylko wtedy, gdy rejestrujesz zrzut stosu podczas rejestrowania przydziałów. Mimo to na stercie prawdopodobnie znajdują się obiekty, które zostały przydzielone przed rozpoczęciem nagrywania, więc przydziały pojawiają się jako pierwsze, po prostu według nazwy klasy.

Lista jest domyślnie sortowana według kolumny Zachowany rozmiar. Aby posortować dane według wartości w innej kolumnie, kliknij jej nagłówek.

Kliknij nazwę klasy, aby otworzyć okno Widok instancji po prawej stronie (jak widać na ilustracji 6). Każde wymienione wystąpienie zawiera te elementy:

  • Głębokość: najkrótsza liczba przeskoków z dowolnego poziomu głównego GC do wybranej instancji.
  • Rozmiar natywny: rozmiar tej instancji w pamięci natywnej. Ta kolumna jest widoczna tylko w Androidzie 7.0 i nowszych.
  • Płytki rozmiar: rozmiar tej instancji w pamięci Java.
  • Przechowywany rozmiar: rozmiar pamięci, w której dominuje ta instancja (zgodnie z drzewem dominującym).

Rysunek 6. Czas trwania potrzebny do wykonania zrzutu stosu jest podany na osi czasu,

Aby sprawdzić stertę, wykonaj te czynności:

  1. Przejrzyj listę, aby znaleźć obiekty z wyjątkowo dużą liczbą sterty i które mogły wyciekły. Jeśli chcesz znaleźć znane klasy, kliknij nagłówek kolumny Nazwa klasy i posortować alfabetycznie. Następnie kliknij nazwę zajęć. Po prawej stronie pojawi się panel Widok instancji z wyszczególnionymi instancjami klasy, jak widać na ilustracji 6.
    • Możesz też szybko znaleźć obiekty, klikając Filtruj lub naciskając Control+F (Command+F na Macu) i wpisując nazwę klasy lub pakietu w polu wyszukiwania. Możesz też wyszukiwać według nazwy metody, jeśli z menu wybierzesz Rozmieść według stosu wywołań. Jeśli chcesz używać wyrażeń regularnych, zaznacz pole obok Wyrażenie regularne. Zaznacz pole Uwzględnij wielkość liter, jeśli w zapytaniu rozróżniana jest wielkość liter.
  2. W panelu Widok instancji kliknij instancję. Poniżej pojawi się karta Odniesienia z wszystkimi odwołaniami do danego obiektu.

    Możesz też kliknąć strzałkę obok nazwy instancji, aby wyświetlić wszystkie jej pola, a następnie kliknąć nazwę pola, aby wyświetlić wszystkie odwołania. Aby wyświetlić szczegóły instancji dla danego pola, kliknij je prawym przyciskiem myszy i wybierz Przejdź do instancji.

  3. Jeśli na karcie Pliki referencyjne znajdziesz odwołanie, które może wyczerpać pamięć, kliknij je prawym przyciskiem myszy i wybierz Przejdź do instancji. Spowoduje to wybranie odpowiedniej instancji ze zrzutu stosu i wyświetlenie jej danych.

W zrzucie stosu wyszukaj wycieki pamięci spowodowane przez:

  • Długotrwałe odniesienia do Activity, Context, View, Drawable i innych obiektów, które mogą zawierać odwołanie do kontenera Activity lub Context.
  • Niestatyczne klasy wewnętrzne, takie jak Runnable, które mogą przechowywać instancję Activity.
  • Pamięci podręczne, w których znajdują się obiekty dłużej niż to konieczne.

Zapisz zrzut stosu jako plik HPROF

Po przechwyceniu zrzutu stosu dane są widoczne w narzędziu do profilowania pamięci tylko wtedy, gdy program profilujący jest uruchomiony. Po zamknięciu sesji profilowania utracisz zrzut stosu. Jeśli więc chcesz go zapisać do późniejszego sprawdzenia, wyeksportuj zrzut stosu do pliku HPROF. W Android Studio w wersji 3.1 i starszych przycisk Eksportuj zapis do pliku znajduje się po lewej stronie paska narzędzi pod osią czasu. W Android Studio w wersji 3.2 i nowszych po prawej stronie każdego wpisu Heap Dump w panelu Sesje znajduje się przycisk Eksportuj zrzut stosu. W wyświetlonym oknie Eksportuj jako zapisz plik z rozszerzeniem .hprof.

Aby użyć innego analizatora HPROF, np. jhat, musisz przekonwertować plik HPROF z formatu Androida na format Java SE HPROF. Możesz to zrobić za pomocą narzędzia hprof-conv dostępnego w katalogu android_sdk/platform-tools/. Uruchom polecenie hprof-conv z 2 argumentami: oryginalnym plikiem HPROF i lokalizacją, w której ma zostać zapisany przekonwertowany plik HPROF. Na przykład:

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

Importuj plik zrzutu stosu

Aby zaimportować plik HPROF (.hprof), kliknij Rozpocznij nową sesję profilowania w panelu Sesje, wybierz Wczytaj z pliku i w przeglądarce plików wybierz plik.

Plik HPROF możesz też zaimportować, przeciągając go z przeglądarki plików do okna edytora.

Wykrywanie wycieku w programie Memory Profiler

Analizując zrzut stosu w programie do profilowania pamięci, możesz filtrować dane profilowania, które według Android Studio mogą wskazywać na wycieki pamięci w instancjach Activity i Fragment w Twojej aplikacji.

Filtr wyświetla następujące typy danych:

  • Activity instancja, która została zniszczona, ale nadal jest przywoływana.
  • Fragment instancji, które nie mają prawidłowego atrybutu FragmentManager, ale nadal się do nich odwołują.

W niektórych sytuacjach, np. w tych sytuacjach, filtr może generować wyniki fałszywie pozytywne:

  • Utworzono Fragment, ale nie był jeszcze używany.
  • Element Fragment jest zapisywany w pamięci podręcznej, ale nie jako część FragmentTransaction.

Aby użyć tej funkcji, najpierw przechwyć zrzut stosu lub zaimportuj plik zrzutu stosu do Android Studio. Aby wyświetlić fragmenty i działania, które mogą powodować wyciek pamięci, zaznacz pole wyboru Wyciek aktywności/fragmentu w panelu zrzutu stosu narzędzia do profilowania pamięci, jak pokazano na ilustracji 7.

Program profilujący: wykrywanie wycieku pamięci

Rysunek 7. Filtruję zrzut stosu pod kątem wycieków pamięci.

Techniki profilowania pamięci

Podczas korzystania z narzędzia do profilowania pamięci należy pracować w swoim kodzie aplikacji w taki sposób, aby wymusić wycieki pamięci. Jednym ze sposobów wywołania wycieków pamięci w aplikacji jest pozostawienie jej przez pewien czas przed sprawdzeniem stosu. Wycieki mogą spływać do góry alokacji na stercie. Im mniejszy wyciek, tym dłużej trzeba uruchomić aplikację, aby móc ją zobaczyć.

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

  • Obracaj urządzenie z pionu na poziomą, a potem kilka razy z powrotem w różnych stanach aktywności. Obracanie urządzenia może często spowodować wyciek obiektu Activity, Context lub View, ponieważ system odtwarza obiekt Activity, a jeśli aplikacja zawiera odniesienie do jednego z tych obiektów w innym miejscu, system nie może tego zrobić.
  • Przełączaj się między aplikacją a inną aplikacją w różnym stanie aktywności (przejdź na ekran główny, a potem wróć do aplikacji).

Wskazówka: powyższe czynności możesz też wykonać za pomocą platformy testowej monkeyrunner.