Z mojego zrozumienia, odśmiecanie pamięci w Javie czyści niektóre obiekty, 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 zostać wyrzucone, ale wszystkie są przywoływane przez inne obiekty.
Jak radzi sobie z tym wyrzucanie elementów bezużytecznych Java? (czy to po prostu wyczerpanie pamięci?)
java
garbage-collection
AlexeyMK
źródło
źródło
Odpowiedzi:
Java GC traktuje obiekty jako „śmieci”, jeśli nie są one osiągalne przez łańcuch rozpoczynający się w katalogu głównym wyrzucania elementów bezużytecznych, więc te obiekty zostaną zebrane. Nawet jeśli obiekty mogą wskazywać na siebie nawzajem, tworząc cykl, nadal są śmieciami, jeśli zostaną odcięte od korzenia.
Zobacz sekcję o nieosiągalnych obiektach w Dodatku A: Prawda o usuwaniu elementów bezużytecznych w wydajności platformy Java: strategie i taktyki, aby uzyskać szczegółowe informacje.
źródło
tak Java Garbage collector obsługuje odwołania cykliczne!
Istnieją specjalne obiekty nazywane korzeniami czyszczenia pamięci (korzenie GC). Są one zawsze osiągalne, podobnie jak każdy obiekt, który ma je u swojego źródła.
Prosta aplikacja Java ma następujące korzenie GC:
Aby określić, które obiekty nie są już używane, JVM sporadycznie uruchamia tak zwany algorytm oznaczania i przeciągania . Działa w następujący sposób
Więc jeśli jakikolwiek obiekt nie jest osiągalny z korzeni GC (nawet jeśli odwołuje się do siebie lub odwołuje się cyklicznie), zostanie poddany czyszczeniu.
Oczywiście czasami może to prowadzić do wycieku pamięci, jeśli programista zapomni wyłuskać obiekt.
Źródło: Java Memory Management
źródło
Moduł odśmiecania pamięci zaczyna się od jakiegoś „głównego” zbioru 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 już to wszystko znajdzie, wszystko inne to śmieci.
Oczywiście istnieje kilka odmian, głównie ze względu na szybkość. Na przykład większość współczesnych modułów odśmiecania pamięci jest „pokoleniowych”, co oznacza, że dzielą obiekty na pokolenia, a gdy obiekt się starzeje, moduł odśmiecania działa coraz dłużej między okresami, w których próbuje dowiedzieć się, czy ten obiekt jest nadal ważny, czy nie. - zaczyna po prostu zakładać, że jeśli żył długo, są całkiem duże szanse, że będzie żył jeszcze dłużej.
Niemniej jednak podstawowa idea pozostaje ta sama: wszystko opiera się na rozpoczęciu od jakiegoś podstawowego zestawu rzeczy, które wydaje się oczywiste, nadal mogą być używane, a następnie gonienie za wszystkimi wskazówkami, aby znaleźć to, co jeszcze może być w użyciu.
Interesujące na marginesie: często ludzie mogą być zaskoczeni stopniem podobieństwa między tą częścią garbage collectora a kodem służącym do organizowania obiektów dla rzeczy takich jak zdalne wywołania procedur. W każdym przypadku zaczynasz od jakiegoś głównego zestawu obiektów i gonisz wskaźniki, aby znaleźć wszystkie inne obiekty, do których się odnoszą ...
źródło
Masz rację. Specyficzna forma czyszczenia pamięci, którą opisujesz, nazywa się „ zliczaniem odwołań ”. Sposób, w jaki to działa (przynajmniej koncepcyjnie większość nowoczesnych implementacji liczenia referencji jest faktycznie implementowanych zupełnie inaczej) w najprostszym przypadku wygląda tak:
I ta prosta strategia ma dokładnie ten problem, który opisałeś: jeśli A odwołuje się do B, a B do A, to ich liczba nigdy nie może być mniejsza niż 1, co oznacza, że nigdy nie zostaną zebrane.
Istnieją cztery sposoby rozwiązania tego problemu:
Nawiasem mówiąc, innym głównym sposobem implementacji garbage collectora (o czym wspomniałem już kilka razy powyżej) jest śledzenie . Kolektor śledzenia opiera się na koncepcji osiągalności . Zaczynasz z pewnym zestawem głównym , o którym wiesz, że jest zawsze osiągalny (na przykład stałe globalne lub
Object
klasa, 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 z obiektów osiągalnych z zestawu głównego i tak dalej, aż uzyskasz domknięcie przechodnie. Wszystko, czego nie ma 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.
źródło
GC Java w rzeczywistości nie zachowują się zgodnie z opisem. Dokładniej jest powiedzieć, że zaczynają się od podstawowego zestawu obiektów, często nazywanych „korzeniami GC”, i zbierają każdy obiekt, do którego nie można dotrzeć z katalogu głównego.
Korzenie GC obejmują takie rzeczy, jak:
Tak więc w twoim przypadku, gdy zmienne lokalne a, b i c wyjdą poza zakres na końcu twojej metody, nie ma już korzeni GC, które zawierają, bezpośrednio lub pośrednio, odniesienie do któregokolwiek z twoich trzech węzłów i będą kwalifikować się do czyszczenia pamięci.
Link TofuBeer zawiera więcej szczegółów, jeśli chcesz.
źródło
Ten artykuł (już niedostępny) dogłębnie na temat garbage collectora (koncepcyjnie ... istnieje kilka implementacji). Odpowiednia część Twojego posta to „A.3.4 Nieosiągalna”:
źródło
Wyrzucanie elementów bezużytecznych zwykle nie oznacza „wyczyść jakiś obiekt, jeśli nic innego nie wskazuje” na ten obiekt (to jest liczenie referencji). Wyrzucanie elementów bezużytecznych z grubsza oznacza znajdowanie obiektów, do których nie można dotrzeć z programu.
W twoim przykładzie, gdy a, b i c wyjdą poza zakres, mogą zostać zebrane przez GC, ponieważ nie masz już dostępu do tych obiektów.
źródło
Bill odpowiedział bezpośrednio na twoje pytanie. Jak powiedział Amnon, twoja definicja czyszczenia pamięci to po prostu zliczanie referencji. Chciałem tylko dodać, że nawet bardzo proste algorytmy, takie jak zaznaczanie i zamiatanie oraz kopiowanie, z łatwością obsługują odwołania cykliczne. Więc nie ma w tym nic magicznego!
źródło