javascript - depurar - paused before potential out of memory crash
Encontrar la fuga de memoria JS en las herramientas de desarrollo de Chrome (3)
Estoy usando las herramientas de desarrollo de Chrome para averiguar si hay una pérdida de memoria en algún código JS. La línea de tiempo de la memoria se ve bien con recuperación de memoria como se esperaba.
Sin embargo, la instantánea de memoria es confusa porque parece que hay una fuga porque hay entradas en "Árbol DOM independiente".
¿Están las cosas en "Árbol DOM independiente" esperando a que se recolecte basura o estas son fugas reales?
Además, ¿alguien sabe cómo saber qué función está reteniendo una referencia a un elemento separado?
¿Están las cosas en "Árbol DOM independiente" esperando a que se recolecte basura o estas son fugas reales?
Antes de tomar una instantánea, el navegador ejecutará la recolección de basura y barrerá todos los objetos a los que no se hace referencia. Entonces, la instantánea del montón siempre contiene solo objetos en vivo. Como consecuencia, si un árbol DOM independiente se encuentra en la instantánea, debe haber un elemento en el árbol al que se haga referencia desde JavaScript.
Además, ¿alguien sabe cómo saber qué función está reteniendo una referencia a un elemento separado?
Debe haber un elemento (o varios de ellos) en el mismo árbol DOM aislado que tiene fondo amarillo. Dichos elementos se referencian desde el código JavaScript. Puede averiguar quién guarda exactamente referencia al elemento en el árbol de retenedores.
Dado que ha agregado la etiqueta jQuery, sospeché furtivamente que esto era una cosa de jQuery. Un google rápido me trajo a esta página . Al utilizar el método de separación de jQ, todavía se guarda en la memoria una referencia al objeto, por lo que podría estar causando su instantánea.
Otra cosa podría ser que jQuery tiene un nodo div
en la mano, que obviamente se guarda en la memoria, pero nunca se agrega al dominio real ... una especie de document.createNode(''div'')
sin agregarlo. Esto también aparecerá en la instantánea de la memoria. No se puede evitar esto, jQuery lo usa para analizar cadenas en elementos html.
Por lo tanto, para eliminar algunos elementos de la memoria, use el memoria .remove()
jQuery .remove()
y suse borrará al instante . El comentario de Esailija sobre por qué remove
no encaja del todo aquí .
$(''#someElem'')[0].parentNode.removeChild($(''#someElem'')[0]);
Debería eliminar el elemento por completo, pero podría no desvincular los eventos. Tal vez algo como:
$(''#someElem'').detach();//to remove any event listeners
$(''#someElem'')[0].parentNode.removeChild($(''#someElem'')[0]);//remove element all together
Y, de nuevo, como señaló Esailija en su respuesta, asegúrese de asignar referencias a cualquier objeto jQuery ( var someRef= $(''.someSelector'');
) a una variable global, ya que no serán sometidos a GC. Solo evite los globales juntos, de hecho.
Pero para responder a su pregunta brevemente, y claramente: no, estas no son fugas de memoria reales , la memoria debe liberarse en el evento onbeforeunload
. El objeto jQuery se elimina, por lo que todas las referencias quedan fuera del alcance. Al menos, eso es lo que mi "investigación" me llevó a creer. Quizás no del todo relevante, pero solo como referencia. Aquí hay una pregunta sobre mem-leaks que publiqué hace un tiempo, y con ella descubrí algunas cosas.
Esos elementos están siendo referenciados en su código, pero están desconectados del árbol DOM principal de la página.
Ejemplo simple:
var a = document.createElement("div");
a
referencia a un elemento desconectado ahora, no puede ser GC cuando a
todavía está en el alcance.
Si los árboles dom separados permanecen en la memoria, entonces estás manteniendo referencias a ellos. Con jQuery es algo fácil hacer esto, solo guarde una referencia a un resultado atravesado y manténgalo así. Por ejemplo:
var parents = $("span").parent("div");
$("span").remove();
Ahora se hace referencia a los intervalos a pesar de que, al parecer, no está haciendo referencia a ellos de todos modos. parents
mantienen indirectamente referencias a todos los tramos a través de la propiedad jQuery .prevObject
. Así que hacer parents.prevObject
daría el objeto que hace referencia a todos los tramos.
Vea el ejemplo aquí http://jsfiddle.net/C5xCR/6/ . Aunque no aparece directamente que se haga referencia a los intervalos, de hecho se hace referencia a ellos por la variable global de los parents
y se puede ver que los 1000 tramos en el árbol DOM independiente nunca desaparecen.
Ahora aquí está el mismo jsfiddle pero con:
delete parents.prevObject
Y puedes ver que los tramos ya no están en el árbol dom separado, o en cualquier otro lugar. http://jsfiddle.net/C5xCR/7/