first before appendto jquery memory-leaks

before - fuga de memoria jQuery con eliminación de DOM



jquery each (6)

Aquí hay una página web muerta que filtra la memoria en IE8 usando jQuery (detecto las pérdidas de memoria observando el uso de memoria de mi proceso iexplore.exe con el tiempo en el Administrador de tareas de Windows):

<html> <head> <title>Test Page</title> <script type="text/javascript" src="jquery.js"></script> </head> <body> <script type="text/javascript"> function resetContent() { $("#content div").remove(); for(var i=0; i<10000; i++) { $("#content").append("<div>Hello World!</div>"); } setTimeout(resetTable, 2000); } $(resetContent); </script> <div id="content"></div> </body> </html>

Aparentemente incluso cuando llamo a la función jQuery.remove() todavía experimento alguna pérdida de memoria. Puedo escribir mi propia función de eliminación que no experimenta pérdida de memoria de la siguiente manera:

$.fn.removeWithoutLeaking = function() { this.each(function(i,e){ if( e.parentNode ) e.parentNode.removeChild(e); }); };

Esto funciona bien y no pierde ninguna memoria. Entonces, ¿por qué jQuery pierde memoria? jQuery.remove() otra función de eliminación basada en jQuery.remove() y esto de hecho causa una fuga:

$.fn.removeWithLeakage = function() { this.each(function(i,e) { $("*", e).add([e]).each(function(){ $.event.remove(this); $.removeData(this); }); if (e.parentNode) e.parentNode.removeChild(e); }); };

Curiosamente, la pérdida de memoria parece ser causada por cada llamada que jQuery incluye para evitar pérdidas de memoria de eventos y datos asociados con los elementos DOM que se eliminan. Cuando llamo a la función removeWithoutLeaking , mi memoria se mantiene constante a lo largo del tiempo, pero cuando llamo removeWithLeakage en removeWithLeakage lugar, simplemente sigue creciendo.

Mi pregunta es, ¿qué pasa con cada llamada

$("*", e).add([e]).each(function(){ $.event.remove(this); $.removeData(this); });

podría estar causando la pérdida de memoria?

EDITAR: corrigió el error en el código que, al volver a probar, demostró no tener ningún efecto sobre los resultados.

NUEVAMENTE EDITAR: He archivado un informe de error con el proyecto jQuery, ya que parece ser un error de jQuery: http://dev.jquery.com/ticket/5285


¿Todavía tiene fugas si llama a empty lugar de remove ?

$("#content").empty();


Consulte la hoja de ruta de jQuery 1.4 en http://docs.jquery.com/JQuery_1.4_Roadmap . Específicamente, la sección "Usar .outerHTML para la limpieza después de .remove ()" trata problemas de pérdida de memoria que ocurren en IE debido a la función de eliminación que se llama.

Quizás sus problemas se resolverán con la próxima versión.


JQuery 1.4.1 tiene lo siguiente:

cleanData: function (elems) { for (var i = 0, elem, id; (elem = elems[i]) != null; i++) { jQuery.event.remove(elem); jQuery.removeData(elem); } }

Esto es lo que tuve que modificar para eliminar el problema de fugas:

cleanData: function (elems) { for (var i = 0, elem, id; (elem = elems[i]) != null; i++) { jQuery.event.remove(elem); jQuery.removeData(elem); jQuery.purge(elem); } }

función agregada:

purge: function (d) { var a = d.childNodes; if (a) { var remove = false; while (!remove) { var l = a.length; for (i = 0; i < l; i += 1) { var child = a[i]; if (child.childNodes.length == 0) { jQuery.event.remove(child); d.removeChild(child); remove = true; break; } else { jQuery.purge(child); } } if (remove) { remove = false; } else { break; } } } },


La eliminación de elementos es un problema DOM inherente. Que se quedará con nosotros Ídem.

jQuery.fn.flush = function() /// <summary> /// $().flush() re-makes the current element stack inside $() /// thus flushing-out the non-referenced elements /// left inside after numerous remove''s, append''s etc ... /// </summary> { return jQuery(this.context).find(this.selector); }

En lugar de hackear jQ, uso esta extensión. Especialmente en las páginas con muchos elimina () y clones ():

$exact = $("whatever").append("complex html").remove().flush().clone();

Y también el siguiente ayuda:

// remove all event bindings , // and the jQ data made for jQ event handling jQuery.unbindall = function () { jQuery(''*'').unbind(); } // $(document).unload(function() { jQuery.unbindall(); });


Parece que se corrigió en jQuery 1.5 (23. versión de febrero). Me encontré con el mismo problema con 1.4.2 y lo arreglé primero con eliminación de dom como se indica arriba y luego probando la nueva versión.


Pensé que David podría tener algo con la supuesta fuga de removeChild, pero no puedo reproducirlo en IE8 ... bien puede suceder en navegadores anteriores, pero eso no es lo que tenemos aquí. Si elimino manualmente los DDs no hay fugas; si outerHTML= '''' jQuery para usar outerHTML= '''' (o move-to-bin seguido de bin.innerHTML) en lugar de removeChild todavía hay una fuga.

En un proceso de eliminación, comencé a hackear bits de remove en jQuery. línea 1244 en 1.3.2:

//jQuery.event.remove(this); jQuery.removeData(this);

Comentando que la línea resultó en ninguna fuga.

Entonces, echemos un vistazo a event.remove, llama data(''events'') para ver si hay algún evento adjunto al elemento. ¿Qué están haciendo los data ?

// Compute a unique ID for the element if ( !id ) id = elem[ expando ] = ++uuid;

Oh. Por lo tanto, agrega una de las propiedades de hackeo de entrada uuid-to-data-jupiter de jQuery para cada elemento en el que incluso intenta leer datos, ¡que incluye a cada descendiente de un elemento que está eliminando! Que tonto. Puedo cortocircuitar eso poniendo esta línea justo antes de ella:

// Don''t create ID/lookup if we''re only reading non-present data if (!id && data===undefined) return undefined;

que parece arreglar la fuga para este caso en IE8. No puedo garantizar que no rompa algo más en el laberinto que es jQuery, pero lógicamente tiene sentido.

Por lo que puedo averiguar, la fuga es simplemente el objeto jQuery.cache (que es el almacén de datos, no es realmente un caché como tal) cada vez más grande a medida que se agrega una nueva clave para cada elemento eliminado. Aunque removeData debería eliminar esas entradas de caché, OK, IE no parece recuperar el espacio cuando delete una clave de un objeto.

(De cualquier manera, este es un ejemplo del tipo de comportamiento de jQuery que no aprecio. Está haciendo demasiado por debajo del capó para lo que debería ser una operación trivialmente simple ... algunas de las cuales son cosas bastante cuestionables. Lo que jQuery hace a innerHTML través de regex para evitar que mostrar como un atributo en IE es simplemente roto y feo. Y el hábito de hacer que getter y setter la misma función es confuso y, aquí, los resultados en el error. )

[Extrañamente, dejar la prueba de fuga durante largos períodos de tiempo terminó ocasionalmente dando errores totalmente espurios en jquery.js antes de que realmente se agotara la memoria ... había algo así como ''comando inesperado'', y noté que ''nodeName es nulo o no un objeto ''en la línea 667, que, por lo que puedo ver, ¡ni siquiera debería haberse ejecutado, y mucho menos que haya una verificación para que nodeName sea nulo! IE no me está dando mucha confianza aquí ...]