2010-09-20 10 views
6

Estoy tratando de visualizar la manipulación de datos modificables dinámicamente con elementos DOM (agregarlos/eliminarlos). Descubrí un comportamiento muy extraño en casi todos los navegadores: después de eliminar un elemento DOM y luego agregar uno nuevo, el navegador no libera la memoria tomada por el elemento DOM eliminado. Vea el código a continuación para entender a qué me refiero. Después de ejecutar esta página, comerá paso a paso hasta 150 MB de memoria. ¿Alguien puede explicarme este extraño comportamiento? ¿O tal vez estoy haciendo algo mal?La adición/eliminación cíclica de nodos DOM causa pérdidas de memoria en 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 al margen: no use una cadena como parámetro para ['setInterval'] (https://developer.mozilla.org/en/DOM/window.setInterval):" No se recomienda el uso de esta sintaxis por las mismas razones que usar [eval()] (https://developer.mozilla.org/En/Core_JavaScript_1.5_Reference/Global_Functions/Eval#Don%27t_use_eval%21) " –

+0

Gracias por la nota Marcel! No sabía esa sintaxis. –

Respuesta

1

No puedo reproducir este en FF 3.6.8/Linux, pero 200 ms para un contador de tiempo es más bien pequeño con que gran parte de DOM re-representación. Lo que noto en mi máquina es que cuando hago cosas intensivas en JavaScript además de ejecutar este script, como escribir en este cuadro de respuesta, el uso de memoria aumenta, pero se vuelve a soltar cuando dejo de escribir (en mi caso, alrededor del 16% de memoria) uso).

Supongo que en su caso el recolector de basura del navegador simplemente no tiene suficiente "tiempo libre" para eliminar realmente esos nodos de la memoria.

+0

Investigué un poco más y descubrí que mis conclusiones iniciales eran erróneas: los navegadores no pierden memoria, la comen hasta cierta cantidad y luego la memoria asignada se cae (y luego comienza a crecer de nuevo paso a paso).) P.ej. La memoria de Chrome crece hasta 150 MB y luego baja a 75MB (¡no a los 7MB iniciales!), El consumo de memoria de IE no crece en absoluto. Extraño, pero antes de preguntar en stackoverflow había observado un consumo constante de memoria que crecía en Chrome, IE y FF y después de que las cosas comenzaron a funcionar como se suponía. Muchas gracias a todos los que preguntaron! –

0

Es debido a la eliminación de un nodo en el árbol DOM, no se borra de la memoria, sigue siendo accesible, por lo que el siguiente código funcionará:

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

Ese código se eliminará el primer hijo de element, y luego, una vez que se haya eliminado, agréguela al final del documento. Realmente no hay nada que puedas hacer, excepto hacer que tu código sea más eficiente con menos eliminaciones.

Para obtener más información, consulte la página Node.removeChild en el Centro de desarrolladores de Mozilla.

+1

Pero si no está asignado a nada (como en el OP), el recolector de basura lo eliminará de la memoria. Esta no es la razón. – slebetman

+0

No, es la razón, aunque no se haya asignado, el recolector de basura no lo eliminará. Incluso 'removed = null' no eliminará la referencia de la memoria, la única forma de hacerlo es actualizar la página. –

+0

Sí, puedo confirmar que existe un recolector de basura y que se recoge eliminado de los elementos DOM. Pero funciona en diferentes navegadores de forma diferente, p. El de Chrome comenzó a funcionar en mi caso solo después de alcanzar unos 150 MB. –

0

No estoy seguro de si afectará el tiempo, y probablemente sea una mala práctica, pero en lugar de pasar por los nodos secundarios, ¿no podría simplemente establecer el innerHTML del div en "" ??

Cuestiones relacionadas