2010-09-20 12 views
6

Sto provando a visualizzare dati modificabili dinamicamente che manipolano con elementi DOM (aggiungendoli/rimuovendoli). Ho scoperto un comportamento molto strano di quasi tutti i browser: dopo aver rimosso un elemento DOM e aggiungerne uno nuovo, il browser non libera la memoria prelevata dall'elemento DOM rimosso. Vedere il codice qui sotto per capire cosa intendo. Dopo aver eseguito questa pagina mangerà passo-passo fino a 150 MB di memoria. Qualcuno può spiegarmi questo strano comportamento? O forse sto facendo qualcosa di sbagliato?L'aggiunta/rimozione ciclica dei nodi DOM causa perdite di memoria in JavaScript?

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0 Transitional//EN"> 
<html> 
<head> 
    <script type="text/javascript"> 
    function redrawThings() { 
     // Removing all the children from the container 
     var cont = document.getElementById("container"); 
     while (cont.childNodes.length >= 1) { 
      cont.removeChild(cont.firstChild); 
     } 

     // adding 1000 new children to the container 
     for (var i = 0; i < 1000; i++) { 
      var newDiv = document.createElement('div'); 
      newDiv.innerHTML = "Preved medved " + i; 
      cont.appendChild(newDiv);    
     }   
    } 
    </script> 
    <style type="text/css"> 
    #container { 
     border: 1px solid blue; 
    } 
    </style> 
</head> 
<body onload='setInterval("redrawThings()", 200);'> 
    <div id="container"> </div> 
</body> 
</html> 
+0

Solo una nota a margine: non utilizzare una stringa come parametro per ['setInterval'] (https://developer.mozilla.org/en/DOM/window.setInterval):" L'uso di questa sintassi non è raccomandato per gli stessi motivi dell'utilizzo di [eval()] (https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Functions/Eval#Don%27t_use_eval%21) " –

+0

Grazie per la nota Marcel! Non sapevo quella sintassi. –

risposta

1

non riesco a riprodurre questo su FF 3.6.8/Linux, ma a 200 ms per un timer è piuttosto piccola, con che gran parte del DOM ri-rendering. Quello che noto sulla mia macchina è che quando si eseguono operazioni intensive di JavaScript oltre all'esecuzione di questo script, ad esempio digitando questa casella di risposta, l'utilizzo della memoria aumenta, ma viene rilasciato nuovamente quando smetto di digitare (nel mio caso, circa il 16% della memoria utilizzo).

Immagino che nel tuo caso il garbage collector del browser non abbia abbastanza 'tempo libero' per rimuovere effettivamente quei nodi dalla memoria.

+0

Ho fatto ulteriori ricerche e ho scoperto che le mie conclusioni iniziali erano sbagliate: i browser non perdevano memoria, lo mangiano fino alla certa quantità e poi la memoria allocata cade (e poi ricomincia a crescere passo dopo passo). Per esempio. La memoria di Chrome cresce fino a 150 MB e poi scende a 75MB (non ai 7MB iniziali però!), Il consumo di memoria di IE non cresce affatto. Strano, ma prima di chiedere su StackOverflow avevo notato un consumo costante di memoria in crescita su Chrome, IE e FF e dopo che le cose iniziarono a funzionare come supposto. Mille grazie a tutti quelli che hanno chiesto! –

0

È perché la rimozione di un nodo da l'Albero DOM non cancella dalla memoria, è ancora accessibile, in modo che il seguente codice funzionerà:

var removed = element.removeChild(element.firstChild); 
document.body.appendChild(removed); 

Che il codice rimuoverà il primo bambino da element, e dopo che è stato rimosso, aggiungilo alla fine del documento. Non c'è davvero nulla che tu possa fare se non rendere il tuo codice più efficiente con meno rimozioni.

Per ulteriori informazioni, consultare la pagina Node.removeChild nel Centro per sviluppatori Mozilla.

+1

Ma se non assegnato a qualcosa (come nell'OP), il garbage collector lo cancellerebbe dalla memoria. Questa non è la ragione. – slebetman

+0

No, è il motivo, anche se non assegnato il garbage collector non lo rimuoverà. Anche 'removed = null' non rimuoverà il riferimento dalla memoria, l'unico modo per farlo è aggiornare la pagina. –

+0

Sì, posso confermare: Garbage Collector esiste e raccoglie rimosso dagli elementi DOM. Ma funziona diversamente su diversi browser, ad es. Quello di Chrome ha iniziato a funzionare nel mio caso solo dopo che raggiunge circa 150 MB. –

0

Non sono sicuro che influisca sui tempi, ed è probabilmente una pratica molto negativa, ma invece di eseguire il ciclo dei nodi figlio, non si può semplicemente impostare l'innerHTML del div a "" ??

Problemi correlati