30

Czy ktoś może wyjaśnić szczegółowo, w jaki sposób silniki JavaScript radzą sobie z odwołaniami cyklicznymi? Czy istnieje duża różnica między przeglądarkami lub nawet plikiem node.js?Kołowe odwołania w JavaScript/Garbage collector

To, o czym mówię, to wyraźne odwołanie do następnego/następnego obiektu. Na przykład:

var objA = { 
    prop: "foo", 
    next: null 
}; 

var objB = { 
    prop: "foo", 
    prev: null 
}; 

objA.next = objB; 
objB.prev = objA; 

Idziemy. Jeśli zrobimy numer console.log(objA), zobaczymy, że stworzyliśmy nieskończony łańcuch. Najważniejsze pytanie brzmi: czy to źle? Czy powoduje wycieki pamięci, gdy nie jest jawnie czyszczony?

Więc mamy do

objA.next = null; 
objB.prev = null; 

lub będzie śmieciarze zająć się nami na konstelacji jak to?

Odpowiedz

53

Każdy przyzwoity śmieciarz będzie obsługiwał cykle.

Cykle są problemem tylko wtedy, gdy wykonujesz naiwne liczenie referencji.

Większość odśmiecaczy nie wykonuje ponownego liczenia (zarówno dlatego, że nie radzi sobie z cyklami, jak i dlatego, że jest nieefektywna). Zamiast tego po prostu podążają za każdym znalezionym referencją, zaczynając od "roots" (zazwyczaj globals i zmiennych opartych na stosie) i zaznaczają wszystko, co mogą znaleźć jako "osiągalny".

Następnie po prostu odzyskują wszystkie inne wspomnienia.

Cykle nie stanowią problemu, ponieważ oznaczają po prostu, że ten sam węzeł zostanie osiągnięty wiele razy. Po raz pierwszy węzeł zostanie oznaczony jako "osiągalny", więc GC będzie wiedział, że już tam był, i pomija węzeł.

Jeszcze bardziej prymitywne GC oparte na liczeniu referencji zwykle implementują algorytmy do wykrywania i łamania cykli.

Krótko mówiąc, nie jest to coś, o co trzeba się martwić. Przypominam sobie, że GC Javascript w IE6 faktycznie nie radził sobie z cyklami (mogłem się mylić, minęło trochę czasu odkąd go przeczytałem, a było dużo, dużo dłużej odkąd dotknąłem IE6), ale we współczesnej implementacji nie ma problemu.

Cały punkt w garbage collector to abstrakcyjne zarządzanie pamięcią. Jeśli musisz zrobić to samemu, Twój GC jest zepsuty.

Aby uzyskać więcej informacji na temat współczesnego zbierania śmieci i używanych algorytmów znakowania i pstrykania, patrz MDN.

+1

Co na temat http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Cosures jest źle? – Sandro

+2

@Sandro ponownie przeczytaj moją odpowiedź. :) Zdrowy GC obsługuje cykle. Wszystko, co jest nowsze niż IE6, można uznać za zdrowe. Jeśli potrzebujesz wsparcia dla IE6, musisz się martwić o jego zepsutą obsługę cykli. Wygląda na to, że przewodnik Google jest napisany przy założeniu, że takie uszkodzone przeglądarki muszą być obsługiwane, więc muszą przejść przez dodatkowe obręcze. – jalf

+0

@Sandro W tym przykładzie dzieje się coś specjalnego: element DOM jest jedną częścią okrągłego odniesienia. Zasadniczo przeciekałbyś pamięć, dopóki nie zamkniesz strony. Jednak jeśli dobrze pamiętam, IE nie zawsze usuwa odniesienia do DOM, kiedy odjeżdżasz. (Wygląda na to, że spowodowało to uszkodzenie stron?) –