Wprowadzenie do zarządzania pamięcią i wycieków pamięci na Androidzie

Warto pamiętać, że podczas gdy to narzędzie może być bardzo przydatne do znalezienia odniesień do podejrzanego wycieku, może być dość trudne i skomplikowane w użyciu do znalezienia nieznanych wycieków i wymaga sporo analizy. Mówiąc to, jeśli go opanujesz – jest to świetne narzędzie do posiadania pod swoim paskiem!

LeakCanary

Obraz z LeakCanary

Innym sposobem na znalezienie wycieków pamięci jest użycie Leak Canary, biblioteki stworzonej przez Square, która pomaga wykrywać wycieki pamięci. Działa ona poprzez użycie klasy ObjectWatcher, która przechowuje słabe referencje do zniszczonych obiektów na stercie. Jeśli referencja nie zostanie usunięta w ciągu następnych pięciu sekund, a Garbage Collector został uruchomiony, obiekt jest uważany za zachowany i rejestruje to jako potencjalny wyciek pamięci w logcat. Całkiem sprytne, prawda?

Aby zacząć, po prostu dodaj bibliotekę wewnątrz swoich zależności do pliku build.gradle, zsynchronizuj i skompiluj.

Dodaj bibliotekę LeakCanary

Jak tylko uruchomisz aplikację, możesz zobaczyć wyjście LeakCanary w logcat, jak obserwuje instanty i zachowuje obiekty. Aby wywołać wyciek, dodałem kilka nowych zadań w mojej aplikacji TaskManager. Niedługo potem dostałem to powiadomienie od LeakCanary, które wskazuje na potencjalny wyciek!

Po prostu kliknij na powiadomienie, aby „zrzucić stertę”, aby zbadać potencjalny wyciek, a to okno dialogowe zostanie wyświetlone w aplikacji.

LeakCanary bada wycieki ..

Leak Canary następnie analizuje stertę poprzez zlokalizowanie zatrzymanych obiektów i znajduje ślad wycieku, który jest ścieżką odniesień do każdego zatrzymanego obiektu. Po wykonaniu tej operacji wyświetlone zostanie powiadomienie podsumowujące liczbę zatrzymanych obiektów i wycieków.

Wygląda na to, że znalazł nasz wyciek! Jeśli klikniemy na niego, zobaczymy pełny ślad przecieku:

Powiada nam, że TaskActivity przecieka, a podkreślone referencje pokazują ślad, przecieka z mContext w SingletonExample – brzmi znajomo! Teraz wiemy, jak znaleźć wyciek za pomocą LeakCanary. 😃

Unikanie wycieków pamięci

Więc teraz, gdy znaleźliśmy nasz wyciek pamięci, jak możemy ich uniknąć w przyszłości? Poniżej znajdują się niektóre z najczęstszych przyczyn i wzorców.

Photo by Bogomil Mihaylov on Unsplash

Odbiorniki rozgłaszania

Odbiorniki rozgłaszania mogą być używane do nasłuchiwania zdarzeń rozgłaszania w całym systemie lub intencji, które wskazują informacje o urządzeniu, takie jak niski poziom baterii, datę i zmiany w łączności – na przykład, że tryb samolotowy został wyłączony. Używając ich, musimy pamiętać, aby wyrejestrować odbiorniki rozgłoszeniowe, w przeciwnym razie nieuchronnie będziemy utrzymywać odniesienie do aktywności.

Jak tego uniknąć: Wszystko, co musisz zrobić, to wywołać unregister() na swoim odbiorniku broadcast w onStop() w swojej aktywności.

Ten wzorzec występuje również dla asyncTask, TimerTask i wątków, które muszą być anulowane w onDestroy(), aby uniknąć wycieku.

Kontekst do klasy Singleton

Czasami potrzebujemy przekazać kontekst z aktywności do klasy Singleton. Przykładem tego może być klasa utils, w której musimy uzyskać dostęp do zasobów, usług lub plików wewnętrznych. Jednak przekazywanie kontekstu oznacza, że nieuchronnie trzymamy się odniesienia do aktywności.

Jak tego uniknąć: Zamiast przekazywać this z aktywności, możemy przekazać kontekst aplikacji, jeśli jest on dostępny (jeśli chcesz dowiedzieć się więcej o tym, kiedy używać jakiego kontekstu, znalazłem ten artykuł naprawdę pomocny!). Alternatywnym rozwiązaniem jest upewnienie się, że ustawiliśmy kontekst Singleton na null wewnątrz metody aktywności onDestroy().

Statyczne referencje

Odniesienie do widoku lub aktywności jako statyczne oznacza, że odniesienie do aktywności nie będzie odśmiecane. Należy tego po prostu unikać przez cały czas.

Jak tego uniknąć: Jeśli z jakiegoś powodu musisz to zrobić, możesz zapewnić, że zostanie zniszczony, ustawiając go na null w onDestroy().

Odniesienia do klas wewnętrznych

Klasy wewnętrzne często powodują wycieki, trzymając niejawne odniesienie do klasy zewnętrznej. Dzieje się tak, gdy zmienna klasy jest zadeklarowana jako statyczna lub gdy sama klasa nie jest zadeklarowana jako statyczna. Mylące? Tak, ale jest to łatwe do uniknięcia, jeśli zastosujemy się do prostej zasady poniżej.

Jak tego uniknąć: Uczyń klasę wewnętrzną statyczną, aby uniknąć trzymania referencji do klasy zewnętrznej i nigdy nie twórz zmiennej statycznej klasy wewnętrznej. To samo odnosi się do klas anonimowych.

To wszystko! Mam nadzieję, że nauczyłeś się kilku rzeczy o wyciekach pamięci i jak ich unikać. Szczęśliwego kodowania! 😄

Oto kilka artykułów i dokumentacji, które uznałem za szczególnie przydatne podczas nauki o wyciekach pamięci:

Dodaj komentarz

Twój adres e-mail nie zostanie opublikowany.