Jak działa Java Garbage Collection z referencjami Circular?

Z mojego zrozumienia, garbage collection w Javie czyści jakiś obiekt, jeśli nic innego nie wskazuje na ten obiekt.

Moje pytanie brzmi, co się stanie, jeśli mamy coś takiego:

class Node {
    public object value;
    public Node next;
    public Node(object o, Node n) { value = 0; next = n;}
}

//...some code
{
    Node a = new Node("a", null), 
         b = new Node("b", a), 
         c = new Node("c", b);
    a.next = c;
} //end of scope
//...other code

a, b, i c powinny być zbierane śmieci, ale wszystkie są przywoływane przez inne obiekty.

Jak sobie z tym radzi Java garbage collection? (czy jest to po prostu wyciek pamięci?)

Author: Marek J, 2009-12-15

8 answers

Gc Javy uważa obiekty za "śmieci", jeśli nie są osiągalne przez łańcuch zaczynający się od korzenia zbioru śmieci, więc obiekty te zostaną zebrane. Nawet jeśli obiekty mogą wskazywać na siebie, tworząc cykl, nadal są śmieciami, jeśli są odcięte od korzenia.

Zobacz sekcję o obiektach nieosiągalnych w Dodatku A: The Truth About Garbage Collection in Java Platform Performance: Strategies and Tactics Aby uzyskać szczegółowe informacje.

 134
Author: Bill the Lizard,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2017-10-11 07:00:28

Yes Java Garbage collector handles circular-reference!

How?

Istnieją specjalne obiekty zwane korzeniami garbage-collection (GC roots). Są one zawsze dostępne, podobnie jak każdy obiekt, który ma je u swojego źródła.

Prosta aplikacja Java ma następujące korzenie GC:

  1. zmienne lokalne w metodzie głównej
  2. główny wątek
  3. zmienne statyczne klasy głównej

Tutaj wpisz opis obrazka

Aby określić, które obiekty nie są JVM działa z przerwami, co jest bardzo trafnie nazywane algorytmem mark-and-sweep . Działa to w następujący sposób

  1. algorytm przemierza wszystkie odniesienia do obiektów, zaczynając od GC korzeni i oznacza każdy znaleziony obiekt jako żywy.
  2. cała pamięć sterty, która nie jest zajęta przez zaznaczone obiekty, jest odzyskane. Jest po prostu oznaczony jako wolny, zasadniczo wolny od nieużywane obiekty.

Więc jeśli jakiś obiekt nie jest osiągalny z korzeni GC(nawet jeśli jest samo-odwołujący się lub cyklicznie odwołujący) zostanie poddany garbage collection.

Oczywiście czasami może to prowadzić do wycieku pamięci, jeśli programista zapomni o dereferencji obiektu.

Tutaj wpisz opis obrazka

Source: Java Memory Management

 109
Author: Aniket Thakur,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2014-10-08 21:06:37

Garbage collector zaczyna się od "głównego" zestawu miejsc, które są zawsze uważane za "osiągalne", takich jak rejestry procesora, stos i zmienne globalne. Działa poprzez znajdowanie wszelkich wskaźników w tych obszarach i rekurencyjne znajdowanie wszystkiego, na co wskazują. Kiedy to wszystko znajdzie, Wszystko inne jest śmieciem.

Istnieje, oczywiście, sporo odmian, głównie ze względu na szybkość. Na przykład większość współczesnych śmieciarzy jest "pokoleniowa", co oznacza, że dziel obiekty na pokolenia, a w miarę starzenia się obiektu, garbage collector jest coraz dłuższy między czasami, kiedy próbuje dowiedzieć się, czy ten obiekt jest nadal ważny, czy nie -- po prostu zaczyna zakładać, że jeśli żył długo, są całkiem spore szanse, że będzie żył jeszcze dłużej.

Niemniej jednak, podstawowa idea pozostaje taka sama: wszystko opiera się na zaczynaniu od jakiegoś podstawowego zestawu rzeczy, które bierze za pewnik, które mogą być nadal używane, a następnie ściganie wszystkich wskazówki, aby znaleźć to, co jeszcze może być w użyciu.

Na marginesie ciekawe: niech ludzie są często zaskoczeni stopniem podobieństwa między tą częścią garbage collector i kodem do tworzenia obiektów dla rzeczy takich jak zdalne wywołania procedur. W każdym przypadku zaczynasz od głównego zestawu obiektów i gonisz za wskaźnikami, aby znaleźć wszystkie inne obiekty, do których się odnoszą...

 10
Author: Jerry Coffin,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-15 20:51:01

Masz rację. Specyficzna forma zbierania śmieci, którą opisujesz, nazywa się " liczenie odniesień ". Sposób działania (przynajmniej koncepcyjnie większość nowoczesnych implementacji zliczania referencji jest faktycznie implementowana zupełnie inaczej) w najprostszym przypadku wygląda tak: {]}

  • za każdym razem, gdy dodawane jest odniesienie do obiektu (np. jest przypisane do zmiennej lub pola, przekazywane do metody itd.), jego liczba odniesień jest zwiększana o 1
  • Gdy a odwołanie do obiektu jest usuwane (metoda zwraca, zmienna wychodzi poza zakres, pole jest ponownie przypisane do innego obiektu lub obiekt, który zawiera To pole, pobiera śmieci), liczba odniesień jest zmniejszona o 1
  • gdy tylko liczba referencji trafi 0, nie ma już odniesienia do obiektu, co oznacza, że nikt nie może go już używać, dlatego jest to śmieci i można go zbierać

I ta prosta strategia ma dokładnie ten problem, który opisałeś: Jeśli a odwołuje się do B i B odwołuje się do A, to oba ich odwołania mogą nigdy być mniejsze niż 1, co oznacza, że nigdy nie zostaną zebrane.

Istnieją cztery sposoby radzenia sobie z tym problemem:

    Zignoruj to. Jeśli masz wystarczająco dużo pamięci, twoje cykle są małe i rzadkie, a czas trwania jest krótki, może uda ci się uciec po prostu nie zbierając cykli. Pomyśl o interpreterze skryptu powłoki: skrypty powłoki zazwyczaj działają tylko przez kilka sekund i nie przydzielają dużo pamięci.
  1. Połącz swój reference counting garbage collector z innym garbage collector, który nie ma problemów z cyklami. CPython robi to na przykład: główny garbage collector w CPython jest reference counting collector, ale od czasu do czasu jest uruchamiany garbage collector do zbierania cykli.
  2. Wykryj cykle. Niestety, wykrywanie cykli na wykresie jest dość kosztowną operacją. W szczególności wymaga prawie tego samego napowietrzne, że kolektor śledzenia, więc można równie dobrze użyć jednego z nich.
  3. nie wdrażaj algorytmu w naiwny sposób, ty i ja: od lat 70. opracowano wiele interesujących algorytmów, które łączą wykrywanie cyklu i liczenie odniesień w jednej operacji w sprytny sposób, który jest znacznie tańszy niż wykonywanie ich osobno lub kolektor śledzenia.

Przy okazji, Inny główny sposób na zaimplementować garbage collector (o czym wspomniałem już kilka razy powyżej), jest tracing . Kolektor śledzenia opiera się na koncepcji osiągalności . Rozpoczynasz od pewnego zestawu głównego , który wiesz, że jest Zawsze osiągalny (na przykład stałe globalne lub klasa Object, bieżący zakres leksykalny, bieżąca ramka stosu) i stamtąd śledzisz wszystkie obiekty, które są osiągalne z zestawu głównego, a następnie wszystkie obiekty, które są osiągalne od obiektów osiągalnych z zestawu głównego i tak dalej, aż do przejścia zamknięcia. Wszystko, co jest nie w tym zamknięciu jest śmieciem.

Ponieważ cykl jest osiągalny tylko w sobie, ale nie jest osiągalny z zestawu głównego, zostanie zebrany.

 8
Author: Jörg W Mittag,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-16 00:04:15

Java GCs nie zachowuje się tak, jak opisujesz. Dokładniejsze jest stwierdzenie, że zaczynają się od podstawowego zestawu obiektów, często nazywanego "GC roots" i będą zbierać każdy obiekt, do którego nie można dotrzeć z korzenia.
GC roots to takie rzeczy jak:

  • zmienne statyczne
  • zmienne lokalne (w tym wszystkie odnośniki "this") aktualnie w stosie działającego wątku

Więc, w Twoim przypadku, gdy zmienne lokalne a, b I c wyjdą z zakresu na koniec twojej metody, nie ma więcej korzeni GC, które zawierają, bezpośrednio lub pośrednio, odniesienie do dowolnego z trzech węzłów, i będą one kwalifikowały się do zbierania śmieci.

Link TofuBeer ma więcej szczegółów, jeśli chcesz.

 5
Author: Sbodd,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-15 20:41:49

Ten artykuł (już niedostępny) zagłębia się w temat garbage collector (koncepcyjnie... istnieje kilka implementacji). Odpowiednią częścią Twojego postu jest "A. 3. 4 Unreachable":

A. 3. 4 nieosiągalny obiekt wchodzi w stan nieosiągalny, gdy nie ma więcej istnieją silne odniesienia do niego. Gdy obiekt jest nieosiągalny, jest to kandydat do zbiórki. Zwróć uwagę na sformułowanie: tylko dlatego, że obiekt jest kandydat do zbiórki nie znaczy, że będzie natychmiast zebrane. JVM może opóźnić odbiór, dopóki nie będzie natychmiastowe zapotrzebowanie na pamięć zużywaną przez obiekt.

 4
Author: TofuBeer,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2018-01-05 02:36:19

Garbage collection zazwyczaj nie oznacza "Wyczyść jakiś obiekt iff nic innego nie wskazuje na ten obiekt" (to zliczanie referencji). Garbage collection oznacza z grubsza znajdowanie obiektów, do których nie można dotrzeć z programu.

Więc w twoim przykładzie, po tym jak a, b I c wyjdą poza zakres, mogą być zbierane przez GC, ponieważ nie masz już dostępu do tych obiektów.

 0
Author: Amnon,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-15 20:39:13

Bill odpowiedział bezpośrednio na twoje pytanie. Jak powiedział Amnon, twoja definicja zbierania śmieci to tylko liczenie referencji. Chciałem tylko dodać, że nawet bardzo proste algorytmy, takie jak mark i sweep i copy collection, z łatwością obsługują odniesienia kołowe. Więc nie ma w tym nic magicznego!

 0
Author: Claudiu,
Warning: date(): Invalid date.timezone value 'Europe/Kyiv', we selected the timezone 'UTC' for now. in /var/www/agent_stack/data/www/doraprojects.net/template/agent.layouts/content.php on line 54
2009-12-15 20:43:32