2015-05-22 27 views
10

Natknąłem się na bibliotekę do wykrywania wycieków pamięci w systemie Android (Java) o nazwie LeakCanary, ale nie rozumiem przykładu, w którym wyciekają one z pamięci. Czy ktokolwiek mógłby wyjaśnić jak i dlaczego kod pokazany w ich przykładzie jest wyciekiem pamięci.Dlaczego to jest wyciek pamięci

class Cat { 
} 
class Box { 
    Cat hiddenCat; 
} 
class Docker { 
    static Box container; 
} 

// ... 

Box box = new Box(); 
Cat schrodingerCat = new Cat(); 
box.hiddenCat = schrodingerCat; 
Docker.container = box; 

a potem oglądać zmienna schrodingerCat szczelność co daje przeciek pokazany następująco (który nie wiem jak odnosić się do powyższego kodu).

* GC ROOT static Docker.container 
* references Box.hiddenCat 
* leaks Cat instance 

Pomoc w wyjaśnieniu wycieku i jego wykrywaniu byłaby bardzo pomocna. Również dobre artykuły dla początkujących byłyby miłe.

Dzięki!

Odpowiedz

13

Najpierw zrozumieć, co jest Memory Leak:

Definicja

Memory Leak to dane przydzielone (bitmapy, obiekty, tablice, itp) w pamięci RAM, które garbage collector (GC) nie może zostać zwolniony, chociaż program już go nie potrzebuje.

Przykład

Użytkownik otwiera który pokazuje obraz. Wgramy bitmapę do pamięci. Teraz użytkownik opuszcza widok, a obraz nie jest już potrzebny i nie ma żadnego odniesienia do niego z kodu. W tym momencie GC wchodzi w czyn i usuwa go z pamięci. ALE, jeśli nadal mieliśmy do tego odniesienie, GC nie będzie wiedział, że to jest w porządku do usunięcia i pozostanie w pamięci RAM zajmującej niepotrzebne miejsce - aka Wyciek pamięci.

kot w pudełku

Powiedzmy, że mamy obiekt Kot w naszej aplikacji, a my trzymać go w obiekcie Box. Jeśli trzymamy pudełko (mamy odniesienie do obiektu Box), a Box zawiera Cat, GC nie będzie w stanie wyczyścić obiektu Cat z pamięci.

Docker to klasa, która ma statyczne odniesienie do naszego pudełka. Oznacza to, że jeśli nie anulujemy go lub nie przypiszemy ponownie wartości, Docker będzie nadal odnosił się do Skrzynki. Zapobieganie usuwaniu skrzynki (i wewnętrznego kota) z pamięci przez GC.

Czy potrzebujemy kota? czy nadal ma znaczenie dla aplikacji?

To zależy od dewelopera, aby zdecydować, jak długo potrzebujemy kota. LeakCanary i inne narzędzia diagnostyczne sugerują możliwy wyciek pamięci. Myślą, że obiekt (Cat) może już nie być potrzebny, więc ostrzegają, że jest to przeciek.

Podsumowanie

Na przykład dają wspólny scenariusz wycieku pamięci. Podczas korzystania z odwołania nie dopuszczamy do czyszczenia obiektu przez GC. Należy przeczytać:

* GC ROOT static Docker.container 
* references Box.hiddenCat 
* leaks Cat instance 

jak:

  • Address Cat potęga nie być już używane, ale nie został usunięty z pamięci przez GC.
  • Powód, dla którego obiekt Cat nie został usunięty, jest związany z tym, że Box ma do niego odniesienie.
  • Powód, dla którego obiekt nie został usunięty, jest oznaczony statycznie.
  • Statyczne odniesienie przez Docker to KORZEŃ drzewa, które powoduje możliwy wyciek.
+1

To wspaniałe wyjaśnienie należy dodać do wiki LeakCanary :) – tieorange

1

Wygląda instancji RefWatcher stosowanego do „oglądać zmiennej schrodingerCat na przecieki”:

refWatcher.watch(schrodingerCat); 

wymusza zestaw GC przechodzi a jeżeli odwołanie przekazywane w nie są zbierane podczas tych GC przechodzi on uważany wyciek.

Od statycznej Docker.container.hiddenCat jest utrzymanie GC zakorzenione odwołanie do obiektu pierwotnie znany jako schrodingerCat, to nie może być GC'ed więc gdy pytasz RefWatcher aby to sprawdzić. Dlatego informuje, że obiekt nie może zostać zebrany.

+1

huh? Czy mógłbyś mi to powiedzieć głupie? :) – Bootstrapper

+0

'Docker.container.hiddenCat' jest statycznym odnośnikiem do obiektu utworzonego jako' schrodingerCat'. Aby obiekt nie mógł być śmieciem zebranym w momencie aktywacji "RefWatchera" dla tego obiektu. –

1

Proponuję przeczytać tę odpowiedź https://stackoverflow.com/a/11908685/1065810

Prawdopodobnie pomóc zrozumieć powyższy przykład.

W skrócie, w twoim przykładzie Docker klasy zachowuje odwołanie do ramki. Nawet gdy kontener nie jest już potrzebny, Docker klasy nadal odwołuje się do niego, powodując przeciek pamięci.

Daj mi znać, jeśli to pomoże.