Sprawdzone metody zarządzania pamięcią

W tym dokumencie zakładamy, że stosujesz sprawdzone metody dotyczące aplikacji na Androida w ramach zarządzania pamięcią, na przykład Zarządzanie pamięcią aplikacji

Wprowadzenie

Wyciek pamięci to rodzaj wycieku zasobów, który występuje, gdy komputer program nie udostępnia przydzielonej pamięci, która nie jest już potrzebna. Przeciek może spowodować, że aplikacja zażąda więcej pamięci od systemu operacyjnego niż ma i powoduje awarię aplikacji. Szereg nieodpowiednich praktyk mogą powodować wycieki pamięci w aplikacjach na Androida, np. nieprawidłową utylizację zasobów lub nie wyrejestrowywać detektorów, gdy nie są już potrzebne.

W tym dokumencie opisujemy kilka sprawdzonych metod, które pomagają zapobiegać i rozwiązywać problemy z wyciekami pamięci w kodzie. Jeśli wypróbowałeś te metody i podejrzewać wyciek pamięci w naszych pakietach SDK, zobacz Jak zgłaszać problemy z pakietami SDK Google

Zanim skontaktujesz się z zespołem pomocy

Zanim zgłosisz wyciek pamięci zespołowi pomocy Google, wykonaj czynności opisane w oraz sprawdzonych metod debugowania w tym dokumencie, aby upewnij się, że kod nie zawiera błędu. Te czynności mogą rozwiązać problem. ale nie, generują informacje potrzebne zespołowi pomocy Google Ci pomóc.

Zapobieganie wyciekom pamięci

Postępuj zgodnie z tymi sprawdzonymi metodami, aby uniknąć kilku najczęstszych przyczyn wycieku pamięci w kodzie, który korzysta z pakietów SDK Google.

Sprawdzone metody dotyczące aplikacji na Androida

Sprawdź, czy w aplikacji na Androida zostały wykonane wszystkie te czynności:

  1. Zwalnianie nieużywanych zasobów
  2. Wyrejestruj detektory, gdy nie są już potrzebne.
  3. Anuluj niepotrzebne zadania.
  4. Przekieruj metody cyklu życia, aby zwolnić zasoby.
  5. Używanie najnowszych wersji pakietów SDK

Szczegółowe informacje o każdej z tych metod znajdziesz w sekcjach poniżej.

Zwolnij nieużywane zasoby

Jeśli Twoja aplikacja na Androida korzysta z zasobu, pamiętaj, by go zwolnić, gdy nie jest już potrzebna. Jeśli tego nie zrobisz, zasób nadal będzie zajmować pamięć nawet po zakończeniu przetwarzania wniosku. Więcej informacji: Cykl życia aktywności w dokumentacji Androida.

Publikowanie nieaktualnych odwołań do GoogleMap w pakietach GeoSDK

Częstym błędem jest to, że obiekt GoogleMap może powodować wyciek pamięci, jeśli jest buforowany przy użyciu NavigationView lub MapView. Mapa Google jest w relacji 1:1 z NavigationView lub MapView, z którego jest pobierany. Ty musi zapewnić, że mapa Google nie jest przechowywana w pamięci podręcznej, lub że odwołanie jest uruchamiany po wywołaniu NavigationView#onDestroy lub MapView#onDestroy. Jeśli za pomocą fragmentów NavigationSupportFragment, MapSupportFragment lub własnego fragmentu. ujęć te widoki, plik referencyjny musi zostać udostępniony w Fragment#onDestroyView.

class NavFragment : SupportNavigationFragment() {

  var googleMap: GoogleMap?

  override fun onCreateView(
    inflater: LayoutInflater,
    parent: ViewGroup?,
    savedInstanceState: Bundle?,
  ): View  {
    super.onCreateView(inflater,parent,savedInstanceState)
    getMapAsync{map -> googleMap = map}
  }

  override fun onDestroyView() {
    googleMap = null
  }
}

Wyrejestruj detektory, gdy nie są już potrzebne

Gdy aplikacja na Androida rejestruje detektor zdarzenia, np. przycisk kliknięcia lub zmiany stanu widoku, pamiętaj, aby wyrejestrować detektor gdy aplikacja nie musi już monitorować zdarzenia. Jeśli tego nie zrobisz, odbiorniki nadal zajmują pamięć nawet po zakończeniu działania aplikacji z nimi.

Załóżmy na przykład, że aplikacja używa pakietu Navigation SDK i wywołuje następujący detektor zdarzeń przyjazdu: addArrivalListener nasłuchuje zdarzeń przyjazdu, powinien również wywołać removeArrivalListener , gdy nie musi już monitorować zdarzeń przyjazdu.

var arrivalListener: Navigator.ArrivalListener? = null

fun registerNavigationListeners() {
  arrivalListener =
    Navigator.ArrivalListener {
      ...
    }
  navigator.addArrivalListener(arrivalListener)
}

override fun onDestroy() {
  navView.onDestroy()
  if (arrivalListener != null) {
    navigator.removeArrivalListener(arrivalListener)
  }

  ...
  super.onDestroy()
}

Anuluj niepotrzebne zadania

Gdy aplikacja na Androida rozpocznie zadanie asynchroniczne, np. pobieranie lub żądania sieciowego, pamiętaj o anulowaniu zadania po jego zakończeniu. Jeśli zadanie nie zostanie anulowana, będzie działać w tle nawet po skończą.

Więcej informacji o sprawdzonych metodach znajdziesz tutaj: Zarządzanie pamięcią aplikacji w dokumentacji Androida.

Przekierowuj metody cyklu życia, aby zwolnić zasoby

Jeśli Twoja aplikacja korzysta z pakietu SDK Navigation lub Maps SDK, pamiętaj, aby udostępnić przez przekazywanie metod cyklu życia (pogrubionych) do navView. Dostępne opcje zrób to za pomocą NavigationView w pakiecie Navigation SDK, MapView w Mapach lub Pakiet SDK do nawigacji. Możesz też użyć SupportNavigationFragment lub SupportMapFragment zamiast bezpośrednio korzystać z NavigationView i MapView, . Fragmenty pomocy obsługują przekazywanie cyklu życia .

class NavViewActivity : AppCompatActivity() {

  override fun onCreate(savedInstanceState: Bundle?) {
    super.onCreate(savedInstanceState)
    ...
    navView = ...
    navView.onCreate(savedInstanceState)
    ...
  }

  override fun onSaveInstanceState(savedInstanceState: Bundle) {
    super.onSaveInstanceState(savedInstanceState)
    navView.onSaveInstanceState(savedInstanceState)
  }

  override fun onTrimMemory(level: Int) {
    super.onTrimMemory(level)
    navView.onTrimMemory(level)
  }

  /* Same with
    override fun onStart()
    override fun onResume()
    override fun onPause()
    override fun onConfigurationChanged(...)
    override fun onStop()
    override fun onDestroy()
  */
}

Używaj najnowszych wersji pakietów SDK

Pakiety SDK Google są nieustannie uzupełniane o nowe funkcje, poprawki błędów poprawy wydajności. Aktualizuj pakiety SDK w aplikacji, aby otrzymywać te dane naprawiania błędów.

Debugowanie wycieków pamięci

Jeśli po wdrożeniu wszystkich odpowiednich funkcji wycieków pamięci nadal występują wcześniej w tym dokumencie, postępuj zgodnie z tą procedurą, aby debugować problem.

Zanim zaczniesz, dowiedz się, jak Android zarządza pamięci. Więcej informacji znajdziesz w sekcji dotyczącej Androida Omówienie zarządzania pamięcią

Aby debugować wycieki pamięci, wykonaj te czynności:

  1. Odtwórz problem. Ten krok jest niezbędny do debugowania.
  2. Sprawdź, czy wykorzystanie pamięci jest oczekiwane Sprawdź, czy parametr zwiększone wykorzystanie, które wygląda na wyciek, nie oznacza tak naprawdę pamięci, wymagane do uruchomienia aplikacji.
  3. Debuguj na poziomie ogólnym. Do wyboru masz kilka funkcji służą do debugowania. 3 różne standardowe zestawy narzędzi pomagają w debugowaniu problemów z pamięcią w Androidzie: Android Studio, Perfetto i Android Debug Bridge (adb) w wierszach poleceń.
  4. Sprawdź wykorzystanie pamięci przez aplikację Zrób zrzut stosu śledzenie alokacji i jej analizowanie.
  5. Napraw wycieki pamięci.

W sekcjach poniżej znajdziesz szczegółowe informacje na temat tych kroków.

Krok 1. Odtwórz problem

Jeśli nie możesz odtworzyć problemu, najpierw zastanów się nad scenariuszami który może doprowadzić do wycieku pamięci. Przeskoczam prosto do spojrzenia zrzut stosu może zadziałać, jeśli problem został odtworzony. Pamiętaj jednak: jeśli po uruchomieniu aplikacji wystąpi zrzut stosu lub z innego losowego momentu, być może nie zostały aktywowane warunki wywołujące wyciek. Rozważ Spróbuj rozwiązać problem w różnych sytuacjach:

  • Jaki zestaw funkcji jest aktywowany?

  • Jaka konkretna sekwencja działań użytkownika powoduje wyciek?

    • Czy próbowałeś/próbowałaś wielokrotnie aktywować tę sekwencję?
  • Przez które stany cyklu życia została przeprowadzona aplikacja?

    • Czy wypróbowałeś/wypróbowałaś kilka iteracji przez różne stany cyklu życia?

Sprawdź, czy możesz odtworzyć problem w najnowszej wersji pakietów SDK. być może został już rozwiązany.

Krok 2. Sprawdź, czy aplikacja wykorzystuje oczekiwane wykorzystanie pamięci

Każda funkcja wymaga dodatkowej pamięci. Podczas debugowania różnych scenariuszy Zastanów się, czy jest to zgodne z oczekiwaniami, czy też wyciek pamięci. Na przykład w przypadku różnych funkcji lub zadań użytkownika weź pod uwagę następujące możliwości:

  • Możliwy wyciek: aktywacja scenariusza przez wiele iteracji powoduje wzrost wykorzystania pamięci.

  • Prawdopodobnie oczekiwane wykorzystanie pamięci: pamięć jest odzyskiwana po scenariuszu. zatrzymuje się.

  • Możliwe oczekiwane wykorzystanie pamięci: wykorzystanie pamięci zwiększa się w okresie a potem traci ważność. Może to być spowodowane ograniczoną pamięcią podręczną lub innymi oczekiwanymi wykorzystanie pamięci.

Jeśli działanie aplikacji jest prawdopodobnie oczekiwane wykorzystanie pamięci, problem może być taki: przez zarządzanie pamięcią aplikacji. Aby uzyskać pomoc, zapoznaj się z artykułem Zarządzanie pamięcią aplikacji

Krok 3. Przeprowadź debugowanie na poziomie ogólnym

Debugowanie wycieku pamięci zacznij od najwyższego poziomu, a następnie przejdź do bardziej szczegółowego widoku po zawężeniu zakresu możliwości. Użyj jednego z tych ogólnych za pomocą narzędzi do debugowania, aby najpierw sprawdzić, czy z czasem wystąpił wyciek:

Program profilujący pamięci Android Studio

Jest to graficzny histogram wykorzystywanej pamięci. Zrzuty stosu i śledzenie alokacji można też aktywować w tym samym interfejsie. Ten to domyślne narzędzie. Więcej informacji: Program profilujący pamięci Android Studio

Liczniki pamięci Perfetto

Perfetto zapewnia precyzyjną kontrolę śledzenie wielu wskaźników i przedstawia je wszystkie na jednym histogramie. Dla: więcej informacji znajdziesz w Liczniki pamięci perfetto.

Interfejs Perfetto

Narzędzia wiersza poleceń AdB (Android Debug Bridge)

Wiele elementów, które można śledzić za pomocą Perfetto, jest również dostępnych jako adb narzędzia wiersza poleceń, do którego można wysyłać zapytania. Kilka ważnych kwestii Przykłady to:

  • Meminfo: wyświetlać szczegółowe informacje o pamięci w określonym momencie.

  • Procstats zapewnia ważne statystyki zbiorcze na przestrzeni czasu.

Istotną statystyką, na którą należy zwrócić uwagę, jest maksymalne wykorzystanie pamięci fizycznej. (maxRSS), których aplikacja wymaga w miarę upływu czasu. Wartość MaxPSS może nie być tak dokładna. Dla: sposób na zwiększenie dokładności, flaga adb shell dumpsys procstats --help –start-testing.

Śledzenie alokacji

Śledzenie alokacji identyfikuje zrzut stosu, gdzie przydzielono pamięć i jeśli nie został uwolniony. Ten krok jest szczególnie przydatny przy śledzeniu wycieków kodu natywnego. Ponieważ to narzędzie identyfikuje zrzut stosu, może być doskonałym rozwiązaniem szybkie zdebugowanie głównej przyczyny lub znalezienie sposobów odtworzenia . Instrukcje korzystania ze śledzenia alokacji: Debuguj pamięć w kodzie natywnym ze śledzeniem alokacji.

Krok 4. Sprawdź wykorzystanie pamięci przez aplikację za pomocą zrzutu stosu

Jednym ze sposobów wykrywania wycieku pamięci jest wykonanie zrzutu stosu aplikacji i i sprawdź, czy nie ma wycieków. Zrzut stosu to zrzut wszystkich obiektów w pamięci aplikacji. Może służyć do diagnozowania wycieków pamięci i innych związane z pamięcią.

Android Studio może wykrywać wycieki pamięci, których nie można naprawić przez GC. Podczas nagrywania zrzutu stosu, Android Studio sprawdza, czy występuje aktywność lub fragment który jest nadal osiągalny, ale został już zniszczony.

  1. Zarejestruj zrzut stosu.
  2. Przeanalizuj zrzut stosu, aby znaleźć wycieki pamięci.
  3. Napraw wycieki pamięci

Szczegółowe informacje znajdziesz w kolejnych sekcjach.

Przechwyć zrzut stosu

Aby przechwycić zrzut stosu, możesz użyć narzędzia Android Debug Bridge (adb) lub pliku Program profilujący pamięci Android Studio.

Używanie narzędzia adb do przechwytywania zrzutu stosu

Aby przechwycić zrzut stosu za pomocą adb, wykonaj te czynności:

  1. Podłącz urządzenie z Androidem do komputera.
  2. Otwórz wiersz polecenia i przejdź do katalogu, w którym znajdują się narzędzia adb.
  3. Aby przechwycić zrzut stosu, uruchom to polecenie :

    adb shell am dumpheap my.app.name $PHONE_FILE_OUT

  4. Aby pobrać zrzut stosu, uruchom to polecenie:

    adb pull $PHONE_FILE_OUT $LOCAL_FILE.

Użyj Android Studio, aby zrobić zrzut stosu

Aby przechwycić zrzut stosu za pomocą narzędzia Android Studio Memory Profiler, wykonaj te czynności: kroków w Androidzie Zrób zrzut stosu .

Przeanalizuj zrzut stosu, aby znaleźć wycieki pamięci

Po zrobieniu zrzutu stosu możesz użyć pamięci Android Studio program profilujący do przeanalizowania. W tym celu wykonaj następujące czynności:

  1. Otwórz projekt na Androida w Android Studio.

  2. Kliknij kolejno Uruchom i Debugowanie.

  3. Otwórz kartę Android Profiler.

  4. Wybierz Pamięć.

  5. Kliknij Otwórz zrzut stosu i wybierz wygenerowany plik zrzutu stosu. Program profilujący pamięci wyświetla wykres wykorzystania pamięci przez aplikację.

  6. Aby przeanalizować zrzut stosu, użyj wykresu:

    • Identyfikowanie obiektów, które nie są już używane.

    • Identyfikuj obiekty, które zużywają dużo pamięci.

    • Sprawdź, ile pamięci używa każdy obiekt.

  7. Użyj tych informacji, aby zawęzić wyniki lub znaleźć źródło wycieku pamięci i jego popraw.

.

Krok 5. Rozwiąż problem z wyciekami pamięci

Gdy poznasz źródło wycieku pamięci, możesz rozwiązać ten problem. Rozwiązanie problemu wycieków pamięci w aplikacjach na Androida pomaga zwiększyć wydajność i stabilność aplikacji. Szczegóły różnią się w zależności od sytuacji. Pomogą jednak następujące sugestie:

Inne narzędzia do debugowania

Jeśli po wykonaniu tych czynności nadal nie udało się znaleźć i rozwiązać problemu wyciek pamięci, wypróbuj te narzędzia:

Debuguj pamięć w kodzie natywnym ze śledzeniem alokacji

Nawet jeśli nie korzystasz bezpośrednio z kodu natywnego, kilka popularnych bibliotek Androida łącznie z pakietami SDK Google. Jeśli uważasz, że wyciek pamięci znajduje się w kodzie natywnym, jest kilku narzędzi i wykorzystać je do debugowania. Śledzenie alokacji za pomocą jednej z tych metod: Android Studio, lub heapprofd (kompatybilne również z Perfetto) jest doskonałym sposobem na identyfikowanie potencjalnych przyczyn gdy wystąpi wyciek pamięci i jest to często najszybszy sposób debugowania.

Śledzenie alokacji ma również tę zaletę, że pozwala udostępniać wyników bez uwzględniania informacji poufnych, które można znaleźć na stercie.

Identyfikuj wycieki za pomocą narzędzia LeakCanary

LeakCanary to zaawansowane narzędzie do identyfikowania wycieków pamięci w aplikacjach na Androida. Aby dowiedzieć się więcej o tym, jak używać LeakCanary w swojej aplikacji, wejdź na LeakCanary.

Jak zgłaszać problemy z pakietami SDK Google

Jeśli wypróbowano metody opisane w tym dokumencie i podejrzewasz wyciek pamięci skontaktuj się z działem obsługi klienta, podając jak najwięcej z poniższych informacji: jak to tylko możliwe:

  • Etapy odtwarzania wycieku pamięci. Jeśli te czynności wymagają skomplikowanego kodowania, pomocne może być skopiowanie kodu, który odtwarza problem do naszej przykładowej aplikacji, i wskaż dodatkowe kroki, które należy wykonać w interfejsie, aby aktywować wyciek danych.

  • Zrzuty stosu zarejestrowane w aplikacji z odtworzonym problemem Przechwyć stertę jest zapisywany w dwóch różnych momentach, które pokazują, że wykorzystanie pamięci znacznie wzrosła.

  • Jeśli spodziewany jest wyciek pamięci natywnej, udostępnij przydział śledzenie danych wyjściowych z heapprofd.

  • Raport o błędzie utworzony po odtworzeniu stanu wycieku.

  • Ślady stosu wszelkich awarii związanych z pamięcią.

    Ważna uwaga: zrzuty stosu zwykle nie wystarczają same w sobie debuguj problem z pamięcią, więc pamiętaj, by podać też jeden z pozostałych formularzy informacji.