30

Qualcuno può spiegare in dettaglio in che modo i motori Javascript gestiscono riferimenti circolari? C'è una grande differenza tra i browser o anche node.js?Riferimenti circolari in Javascript/Garbage collector

Quello di cui sto parlando è un esplicito riferimento indietro/successivo all'interno degli oggetti. Ad esempio:

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

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

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

Ci siamo. Se facciamo un console.log(objA) possiamo vedere che abbiamo creato una catena infinita. La grande domanda è, è così male? Crea perdite di memoria quando non viene pulito in modo esplicito?

Quindi dobbiamo

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

o saranno i netturbini prendersi cura di noi su costellazioni come questo?

risposta

53

Qualsiasi raccoglitore di rifiuti decente gestirà i cicli.

I cicli sono solo un problema se si esegue il conteggio dei riferimenti ingenuo.

La maggior parte dei garbage collector non esegue il conteggio dei ref (sia perché non può gestire i cicli, sia perché è inefficiente). Invece, seguono semplicemente ogni riferimento che riescono a trovare, a partire da "root" (generalmente globali e variabili basate sullo stack) e contrassegnano tutto ciò che possono trovare come "raggiungibile".

Quindi semplicemente recuperano tutta l'altra memoria.

I cicli non sono un problema perché indicano semplicemente che lo stesso nodo verrà raggiunto più volte. Dopo la prima volta, il nodo sarà già contrassegnato come "raggiungibile", quindi il GC saprà che è già presente e salterà il nodo.

GC ancora più primitivi basati sul conteggio dei riferimenti di solito implementano algoritmi per rilevare e interrompere i cicli.

In breve, non è qualcosa di cui ti devi preoccupare. Mi sembra di ricordare che il Javascript GC di IE6 in realtà non è riuscito a gestire i cicli (potrei sbagliarmi, è passato un po 'di tempo da quando l'ho letto ed è passato molto tempo da quando ho toccato IE6), ma in qualsiasi implementazione moderna, è nessun problema.

L'intero punto in un garbage collector è di astrarre la gestione della memoria. Se devi farlo da solo, il tuo GC è rotto.

Vedere MDN per ulteriori informazioni sulla moderna garbage collection e gli algoritmi di mark-and-sweep utilizzati.

+1

Che dire di http://google-styleguide.googlecode.com/svn/trunk/javascriptguide.xml?showone=Closures#Closures è sbagliato? – Sandro

+2

@Sandro leggi di nuovo la mia risposta. :) Un GC corretto gestisce i cicli bene. Tutto ciò che è più nuovo di IE6 può essere considerato sano di mente. Se è necessario supportare IE6, è necessario preoccuparsi della sua gestione dei cicli interrotta. Apparentemente, la guida di Google è stata scritta partendo dal presupposto che tali browser danneggiati devono essere supportati, quindi devono passare attraverso alcuni loop aggiuntivi. – jalf

+0

@Sandro C'è qualcosa di speciale in questo esempio: un elemento DOM è una parte del riferimento circolare. In generale, si perderebbe memoria fino a chiudere la pagina. Se ricordo correttamente, tuttavia, IE non rimuove sempre i riferimenti al DOM quando si naviga. (Apparentemente facendo questo ha rotto alcune pagine?) –