2010-01-04 10 views

Respuesta

28

La gran mayoría de las fugas que hablar con JavaScript se encuentra específicamente en IE6-7 cuando se hace un ciclo de referencia entre objetos JavaScript y objetos host como nodos DOM.

En IE6 esto es particularmente pernicioso en el sentido de que no recupera la memoria cuando sale de la página; se ha ido hasta que salgas del navegador. En IE7, borrar la página ahora devuelve la memoria, pero aún puede tener dificultades cuando tiene una aplicación de larga ejecución. IE8 soluciona la mayor parte de este problema de manera adecuada convirtiendo los nodos DOM en objetos JavaScript nativos en lugar de objetos host. (Todavía podría desencadenar las filtraciones en IE8 al incluir otros objetos no nativos como objetos ActiveX en un bucle de referencia.)

Todavía habrá pequeñas pérdidas de memoria oscuras al acecho en lugares aleatorios para todos los navegadores, especialmente en versiones anteriores. Pero no hay una sola forma de categorizar fácilmente y evitarlos como con el problema de reintroducción de IE.

+1

+1: tiempo buscado para este perl de la sabiduría. –

+0

@Marco Demaio Hmm, este http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/leak.html todavía se filtra en IE9 en modo estándar o peculiar (win7 64bit), asegúrese de utilizar el explorador de procesos cuando se supervisen los bytes privados .. suspiro .. –

+0

@AlexanderN: en realidad en IE8 WXP la página que sugirió no tiene fugas. Utilizo el simple "Administrador de tareas de Windows" (pestaña "Rendimiento") para ver si la página tiene fugas, en tal caso vería que el "Uso de PF" aumenta más y más. –

17

Para añadir a bobince respuesta, hice algunas pruebas con IE8.

Probé casi todos los ejemplos proporcionados en http://www.javascriptkit.com/javatutors/closuresleak/index.shtml

Sin uno de ellos tiene una fuga de memoria más (al menos no de una manera perceptible), excepto el ejemplo que elimina nodos hijos con eventos todavía unidos a ellos.

Este tipo de ejemplo creo que es mejor explicado por Douglas Crockford en su queuetest2.

Ésta continúan las fugas de memoria en IE8 y es bastante fácil de probar simplemente ejecutando the test script y mirando al Administrador de tareas de Windows - Rendimiento - PF uso. Verás que el uso de PF aumenta en casi 1 MB por ciclo (muy rápido).

Pero en IE8 la memoria se libera en la página de descarga (como navegar a una nueva página o volver a cargar la misma página) y, obviamente, también cuando se cierra totalmente el navegador.

Para que el usuario final perciba que esta memoria tiene fugas en IE8 (como rendimiento systerm reducido), necesita permanecer en la misma página durante mucho tiempo, lo que en la actualidad puede ocurrir con frecuencia con AJAX, pero esta página también necesita hacer cientos de niños eliminando elementos con eventos adjuntos.

prueba de Douglas Crockford estresando el navegador con 10000 nodos añadidos y luego eliminados, eso es excelente para mostrarle el problema, pero en la vida real nunca tuve una página que eliminara más de 10 elementos.INMHO por lo general es más rápido usar display: none en lugar de eliminar un conjunto completo de nodos, es por eso que no uso removeChild tanto.


Porque el que podrían estar más interesados ​​en la pérdida de memoria IE8 se ha explicado anteriormente, lo hice otra prueba y parece fugas MEM no aparecen en absoluto en IE8 cuando se utiliza innerHTML en lugar de appendChild/removeChild añadir/eliminar elementos secundarios con eventos adjuntos. Así que al parecer Douglas Crockford purge function (sugerido por él para evitar pérdidas de memoria en el IE) ya no es necesario en IE8 al menos cuando se utiliza innerHTML ...

(EDITADO gracias a 4esn0k comentario abajo) ... además Douglas Crockford purge function NO funciona en IE8, en su código var a = d.attributes devuelve atributos NO onclick (o cualquier otro atributo onevent) que se agregaron en el tiempo de ejecución en IE8 (se devuelven en IE7).

Douglas Crockford dice:

"La función de purga debe ser llamado antes de retirar cualquier elemento, ya sea por el método removeChild, o mediante el establecimiento de la propiedad innerHTML ."

que proporcionan el código aquí la prueba:

<body>  
    <p>queuetest2 similar to the one provided by Douglas Crockford 
    at http://www.crockford.com/javascript/memory/leak.html 
    <br>but this one adds/removes spans using innerHTML 
    instead of appendChild/removeChild.</p> 

    <div id="test"></div>  
    <script> 
     /* ORIGINAL queuetest2 CODE FROM DOUGLAS CROCKFORD IS HERE 
      http://www.crockford.com/javascript/memory/queuetest2.html */ 

     (function (limit, delay) 
     { 
      var n = 0; 
      var add = true; 

      function makeSpan(n) 
      { 
       var div = document.getElementById('test'); 
       //adding also an inline event to stress more the browser 
       div.innerHTML = "<span onmouseover=\"this.style.color = '#00ff00';\">" + n + "</span>"; 
       var s = div.getElementsByTagName('span')[0]; 
       s.onclick = function(e) 
       { 
        s.style.backgroundColor = 'red'; 
        alert(n); 
       }; 
       return s; 
      } 

      function process(n) 
      { 
       if(add)      
       s = makeSpan(n); 
       else 
       s.parentNode.innerHTML = ""; //removing span by clearing the div innerHTML 
       add = !add; 
      } 

      function loop() 
      { 
       if (n < limit) 
       { 
        process(n); 
        n += 1; 
        setTimeout(loop, delay); 
       } 
      } 

      loop(); 
     })(10000, 10); 

    </script> 
</body> 
+0

¿La función de purga "Douglas Crockford" es útil para IE 8 aquí? Parece que, dado que IE8 (en modo IE8, modo no compatible) "s.onclick" no está asignado al atributo "onclick", purga no puede encontrar "onclick" en los atributos. Estoy en lo correcto? – 4esn0k

+0

@ 4esn0k: lo siento, pero no estoy seguro de lo que quiere decir. –

+1

var s = document.createElement ('div'); s.onclick = function() {}; var a = s.attributes; para (var i = 0; i 4esn0k

Cuestiones relacionadas