28

Considerate questa citazione da the Mozilla Docs on JavaScript memory leaks:DOM: perché si tratta di una perdita di memoria?

function addHandler() { 
    var el = document.getElementById('el'); 
    el.onclick = function() { 
     this.style.backgroundColor = 'red'; 
    } 
} 

Il codice di cui sopra imposta l'elemento a diventare rosso quando viene cliccato. Lo crea anche una perdita di memoria. Perché? Perché il riferimento a el è catturato inavvertitamente nella chiusura creata per la funzione interna anonima . Questo crea un riferimento circolare tra un oggetto JavaScript (la funzione) e un oggetto nativo (el).

Si prega di spiegare i motivi di perdita di cui sopra in modo semplice e conciso, non sto ottenendo il punto esatto.

Il sito/la pagina presenta un problema di sicurezza a causa della perdita? Come li evito? Quale altro codice può causare perdite di memoria? Come posso sapere quando si è verificata una perdita di memoria?

Sono un principiante assoluto sul tema delle perdite di memoria. Qualcuno potrebbe chiarire questa cosa per me, passo dopo passo? Qualcuno può aiutarmi a chiarire questa affermazione? "Questo crea un riferimento circolare tra un oggetto JavaScript (la funzione) e un oggetto nativo (el)."

+1

http://www.javascriptkit.com/javatutors/closuresleak/, http://www.google.com/search?q=explanation+of+javascript+memory+leaks – CBroe

+1

@GrantKiely sua da MDN –

+0

http: //javascript.crockford.com/memory/leak.html – undefined

risposta

16

Ci sono due concetti che ti aiuteranno a capire questo esempio.

1) chiusure

La definizione di una chiusura che è Every inner function enjoys access to its parent's function variables and parameters.

Quando la funzione addHandler() termina, la funzione anonima ha ancora accesso alla variabile el del genitore.

2) Funzioni = memoria

Ogni volta che si definisce un function viene creato un nuovo oggetto. Ciò che rende questo esempio un po 'confuso è che onclick è un evento che può essere impostato solo su un elemento DOM una volta.

Quindi sicuramente el.onclick = function(){}; sovrascriverà solo la vecchia funzione, giusto?

Errore! ogni volta che viene eseguito addHandler, viene creato un nuovo oggetto funzione.

In conclusione:

Ogni volta che la funzione esegue creerà un nuovo oggetto, con chiusura contenente el. Visto che la funzione anonima mantiene l'accesso a el, il garbage collector non può rimuoverlo dalla memoria.

La funzione anon manterrà l'accesso a el, ed el ha accesso alla funzione, ovvero un riferimento circolare, che causa una perdita di memoria in IE.

+8

* "In questo caso,' this' si riferisce a el. "* ... è vero, ma questo fatto particolare non ha nulla a che fare con le chiusure. Questa è una proprietà dei gestori di eventi, che siano o meno chiuse. Il fatto che 'el' sia accessibile nella funzione interna è importante. –

+0

@Grant Kiely Felix ha ragione. –

+0

@FelixKling Grazie! Ho rimosso quella parte dalla mia risposta. – gkiely

7

Ogni volta che si definisce una funzione in JavaScript, viene creata una execution context; tale contesto di esecuzione contiene riferimenti a tutte le variabili della catena campo di applicazione, a partire dal campo di applicazione globale tutta la strada fino al campo di applicazione locale:

function test() 
{ 
    var el = document.getElementById('el'); 
    el.onclick = function() { 
     // execution context of this function: el, test 
     alert('hello world'); 
    } 
} 

Quando test() è fatto, la funzione anonima non è ancora riciclato perché è ora assegnato ad un elemento del DOM; vale a dire che è riferito a da una proprietà dell'elemento DOM.

Allo stesso tempo, l'elemento DOM stesso è anche parte del contesto di esecuzione della funzione e ora non può essere riciclato a causa del riferimento ciclico, anche se non è immediatamente evidente che è effettivamente utilizzato; puoi trovare una dimostrazione di ciò in this answer.

Detto questo, al giorno d'oggi, la maggior parte dei motori JavaScript (anche quelli che si trovano in IE) Utilizzare un più avanzato garbage collector in grado di identificare le variabili non utilizzate un bel po 'meglio, utilizzando tecniche come mark-and-sweep o garbage collection generazionale/effimero.

Per essere sicuri di non incorrere in problemi su qualsiasi del browser (anche se, a causa della tipica durata di vita di una pagina, questo è in gran parte teorica):

document.getElementById('el').onclick = function() { 
    alert('hello world'); 
} 
+0

non è riuscito a ottenere questo "ma el non viene anche riciclato perché fa parte del contesto di esecuzione di quella funzione". –

+1

@Maizere Il contesto di esecuzione contiene (o piuttosto riferimenti) 'el' e pertanto non può essere riciclato a causa del conteggio dei riferimenti. –

+0

quindi provoca una perdita di memoria ??? –

1

Vedere anche la sezione di more information l'articolo MS sul problema:

Questa perdita di memoria si verifica perché gli oggetti DOM sono oggetti non JScript. Gli oggetti DOM non si trovano nello schema di garbage collection mark-and-sweep di JScript. Pertanto, il riferimento circolare tra gli oggetti DOM e i gestori JScript non verranno interrotti fino a quando il browser non completamente strappa la pagina.

ma nota che a differenza di quanto indicato in tale articolo (memoria verrà recuperata quando il browser va ad una nuova pagina), this article conferma che un bug in IE 6 ha causato la memoria da trapelato per sempre.

1

La gestione della memoria di JavaScript di solito funziona in questo modo: "finché è possibile raggiungerlo, mantienilo". Questo è fondamentalmente il paradigma che sta dietro a qualsiasi modello di memoria basato sulla raccolta di dati inutili.

I raccoglitori di immondizie tendono ad essere molto bravi in ​​quello che fanno, rilevano anche se un determinato gruppo di elementi è raggiungibile solo all'interno di questo gruppo di elementi. Questi gruppi sono anche chiamati riferimenti circolari, poiché se segui i riferimenti finirai in un elemento che hai già visitato: hai eseguito una cerchia.

Tuttavia, nel tuo esempio hai in realta 'due oggetti provenienti da due diversi "mondi":

Circular references

Internet Explorer utilizza il proprio schema di garbage collection per questo, separato dal meccanismo utilizzato da JavaScript . È l'interazione tra i due che può causare perdite di memoria.

E questo è esattamente ciò che accade e può causare perdite di memoria.

Problemi correlati