Che cos'è la garbage collection JavaScript? Cosa è importante che un programmatore web capisca sulla raccolta dei rifiuti di JavaScript, al fine di scrivere codice migliore?
Che cos'è la garbage collection JavaScript? Cosa è importante che un programmatore web capisca sulla raccolta dei rifiuti di JavaScript, al fine di scrivere codice migliore?
Risposte:
Eric Lippert ha scritto un post di blog dettagliato su questo argomento qualche tempo fa (confrontandolo inoltre con VBScript ). Più precisamente, ha scritto su JScript , che è l'implementazione di Microsoft di ECMAScript, sebbene molto simile a JavaScript. Immagino che si possa presumere che la stragrande maggioranza dei comportamenti sarebbe la stessa per il motore JavaScript di Internet Explorer. Naturalmente, l'implementazione varierà da browser a browser, anche se sospetto che potresti prendere una serie di principi comuni e applicarli ad altri browser.
Citato da quella pagina:
JScript utilizza un garbage collector mark-and-sweep non generazionale. Funziona così:
Ogni variabile che è "nell'ambito" è chiamata "scavenger". Uno scavenger può riferirsi a un numero, un oggetto, una stringa, qualunque cosa. Manteniamo un elenco di scavenger - le variabili vengono spostate nell'elenco scav quando entrano nell'ambito e fuori dall'elenco scav quando escono dall'ambito.
Ogni tanto viene eseguito il garbage collector. Innanzitutto mette un "segno" su ogni oggetto, variabile, stringa, ecc. - Tutta la memoria tracciata dal GC. (JScript utilizza internamente la struttura di dati VARIANT e ci sono molti bit inutilizzati in più in quella struttura, quindi ne abbiamo appena impostato uno.)
In secondo luogo, cancella il segno sugli spazzini e sulla chiusura transitiva dei riferimenti degli spazzini. Quindi se un oggetto scavenger fa riferimento a un oggetto non scavenger, allora cancelliamo i bit sul non scavenger e su tutto ciò a cui si riferisce. (Sto usando la parola "chiusura" in un senso diverso rispetto al mio post precedente.)
A questo punto sappiamo che tutta la memoria ancora contrassegnata è allocata memoria che non può essere raggiunta da nessun percorso da nessuna variabile nell'ambito. Tutti quegli oggetti sono istruiti a demolirsi, il che distrugge qualsiasi riferimento circolare.
Lo scopo principale della garbage collection è di consentire al programmatore di non preoccuparsi della gestione della memoria degli oggetti che creano e usano, anche se ovviamente a volte non è possibile evitarlo - è sempre utile avere almeno un'idea approssimativa di come funziona la garbage collection .
Nota storica: una precedente revisione della risposta aveva un riferimento errato delete
all'operatore. In JavaScript l' delete
operatore rimuove una proprietà da un oggetto ed è completamente diverso da delete
in C / C ++.
delete
modo errato; ad esempio nel primo esempio, invece di delete foo
, devi prima rimuovere il listener di eventi tramite window.removeEventListener()
e poi usare foo = null
per sovrascrivere la variabile; in IE, delete window.foo
(ma non delete foo
) avrebbe funzionato anche se foo
fosse globale, ma anche allora non avrebbe funzionato in FF o Opera
delete
è un operatore unario (un'espressione), non un'affermazione (cioè:) delete 0, delete 0, delete 3
. Sembra una dichiarazione quando espressa da una dichiarazione di espressione.
Fai attenzione ai riferimenti circolari quando sono coinvolti oggetti DOM:
Schemi di perdita di memoria in JavaScript
Tieni presente che la memoria può essere recuperata solo quando non ci sono riferimenti attivi all'oggetto. Questa è una trappola comune con chiusure e gestori di eventi, in quanto alcuni motori JS non verificheranno a quali variabili effettivamente si fa riferimento nelle funzioni interne e manterranno semplicemente tutte le variabili locali delle funzioni che lo racchiudono.
Ecco un semplice esempio:
function init() {
var bigString = new Array(1000).join('xxx');
var foo = document.getElementById('foo');
foo.onclick = function() {
// this might create a closure over `bigString`,
// even if `bigString` isn't referenced anywhere!
};
}
Un'implementazione ingenua di JS non può essere raccolta bigString
fintanto che il gestore dell'evento è presente. Esistono diversi modi per risolvere questo problema, ad esempio l'impostazione bigString = null
alla fine di init()
( delete
non funzionerà per le variabili locali e gli argomenti delle funzioni: delete
rimuove le proprietà dagli oggetti e l'oggetto variabile è inaccessibile - ES5 in modalità rigorosa lancerà anche un ReferenceError
se provi per cancellare una variabile locale!).
Consiglio di evitare il più possibile chiusure inutili se ti interessa il consumo di memoria.
Buona citazione tratta da un blog
Il componente DOM è "garbage collection", così come il componente JScript, il che significa che se si crea un oggetto all'interno di uno dei componenti e si perde traccia di quell'oggetto, alla fine verrà pulito.
Per esempio:
function makeABigObject() {
var bigArray = new Array(20000);
}
Quando si chiama quella funzione, il componente JScript crea un oggetto (chiamato bigArray) accessibile all'interno della funzione. Non appena la funzione ritorna, però, "perdi traccia" di bigArray perché non c'è più modo di farvi riferimento. Bene, il componente JScript si rende conto che ne hai perso la traccia, e così bigArray viene ripulito: la sua memoria viene recuperata. Lo stesso tipo di cose funziona nel componente DOM. Se dici document.createElement('div')
, o qualcosa di simile, il componente DOM crea un oggetto per te. Una volta che hai perso traccia di quell'oggetto in qualche modo, il componente DOM pulirà il relativo.
Per quanto ne so, gli oggetti JavaScript vengono periodicamente raccolti in modo inutile quando non ci sono riferimenti all'oggetto. È qualcosa che accade automaticamente, ma se vuoi vedere di più su come funziona, a livello C ++, ha senso dare un'occhiata al codice sorgente WebKit o V8
In genere non è necessario pensarci, tuttavia, nei browser più vecchi, come IE 5.5 e le prime versioni di IE 6, e forse le versioni attuali, le chiusure creerebbero riferimenti circolari che se non controllati finirebbero per consumare memoria. Nel caso particolare che intendo per le chiusure, è stato quando hai aggiunto un riferimento JavaScript a un oggetto dom e un oggetto a un oggetto DOM che faceva riferimento all'oggetto JavaScript. Fondamentalmente non potrebbe mai essere raccolto e alla fine farebbe diventare instabile il sistema operativo nelle app di test che creavano loop per creare arresti anomali. In pratica, queste perdite sono generalmente piccole, ma per mantenere pulito il codice è necessario eliminare il riferimento JavaScript all'oggetto DOM.
Di solito è una buona idea usare la parola chiave delete per de-referenziare immediatamente oggetti di grandi dimensioni come i dati JSON che hai ricevuto e fatto tutto ciò che ti serve, specialmente nello sviluppo web mobile. Questo fa sì che il prossimo sweep del GC rimuova quell'oggetto e liberi la sua memoria.
mark-and-sweep
algoritmi di stile più recenti si occupano di questo .
garbage collection (GC) è una forma di gestione automatica della memoria rimuovendo gli oggetti che non sono più necessari.
qualsiasi processo relativo alla memoria segua questi passaggi:
1 - alloca lo spazio di memoria che ti serve
2 - eseguire alcune elaborazioni
3 - libera questo spazio di memoria
ci sono due algoritmi principali utilizzati per rilevare quali oggetti non sono più necessari.
Garbage collection conteggio dei riferimenti : questo algoritmo riduce la definizione di "un oggetto non è più necessario" a "un oggetto non ha altri oggetti che fanno riferimento ad esso", l'oggetto verrà rimosso se nessun punto di riferimento ad esso
Algoritmo Mark-and-sweep : collega ogni oggetto alla sorgente principale. qualsiasi oggetto non si connette alla radice o ad altri oggetti. questo oggetto verrà rimosso.
attualmente i browser più moderni utilizzano il secondo algoritmo.
"Nell'informatica, la garbage collection (GC) è una forma di gestione automatica della memoria. Il garbage collector, o solo il collector, tenta di recuperare immondizia, o memoria utilizzata da oggetti a cui non accederà o muterà mai più l'applicazione".
Tutti i motori JavaScript hanno i propri garbage collector e possono differire. La maggior parte delle volte non devi occuparti di loro perché fanno semplicemente quello che dovrebbero fare.
Scrivere un codice migliore dipende principalmente da quanto conosci i principi di programmazione, il linguaggio e l'implementazione particolare.
Che cos'è la garbage collection JavaScript?
controlla questo
Cosa è importante che un programmatore web capisca sulla raccolta dei rifiuti di JavaScript, al fine di scrivere codice migliore?
In Javascript non ti interessa l'allocazione e la deallocazione della memoria. L'intero problema è richiesto all'interprete Javascript. Le perdite sono ancora possibili in Javascript, ma sono bug dell'interprete. Se sei interessato a questo argomento, puoi leggere di più in www.memorymanagement.org
Su Windows puoi usare Drip.exe per trovare perdite di memoria o verificare se la tua routine di mem libera funziona.
È davvero semplice, basta inserire un URL del sito Web e vedrai il consumo di memoria del renderer IE integrato. Quindi premi aggiorna, se la memoria aumenta, hai trovato una perdita di memoria da qualche parte sulla pagina web. Ma questo è anche molto utile per vedere se le routine per liberare memoria funzionano per IE.
I tipi di riferimento non memorizzano l'oggetto direttamente nella variabile a cui è assegnato, quindi la variabile oggetto in questo esempio in realtà non contiene l'istanza dell'oggetto. Al contrario, contiene un puntatore (o riferimento) alla posizione in memoria in cui esiste l'oggetto
var object = new Object();
se si assegna una variabile a un'altra, ogni variabile ottiene una copia del puntatore ed entrambi fanno ancora riferimento allo stesso oggetto in memoria.
var object1 = new Object();
var object2 = object1;
JavaScript è un linguaggio spazzatura , quindi non è necessario preoccuparsi delle allocazioni di memoria quando si utilizzano i tipi di riferimento. Tuttavia, è meglio dereference oggetti che non è più necessario in modo che il garbage collector può liberare quella memoria. Il modo migliore per farlo è impostare la variabile oggetto su null.
var object1 = new Object();
// do something
object1 = null; // dereference
Dereferenziare oggetti è particolarmente importante in applicazioni molto grandi che utilizzano milioni di oggetti.
da I principi di JavaScript orientato agli oggetti - NICHOLAS C. ZAKAS