2012-02-16 14 views
14

Veo que los controladores de eventos registrados a través de .on() se encuentran en $.cache. También veo que los controladores de eventos también se mantienen en $(elem).data().

Los objetos contenidos en $.cache se refieren a los nodos DOM en los que se registran los eventos. Esto lleva a la pérdida de memoria cuando los nodos DOM están separados, y esto hace que las llamadas a .off() sean obligatorias.

Tengo una situación en la que no sé cuándo se desconectará el nodo DOM (al que adjunté el controlador de eventos). Si bien puedo mantener la referencia a ese nodo DOM en mi código y llamar al .off() para limpiar, no me parece agradable, porque no es sencillo saber cuándo se eliminará el nodo DOM.

¿Cuál es la mejor manera de hacerlo?

Respuesta

16

"¿Cuál es la mejor manera de hacer esto?"

Si vas a usar jQuery, que debe usar su API para la eliminación de elementos, y debe utilizar los métodos adecuados, de lo contrario, como ha afirmado, tendrá pérdidas de memoria.

Si no sabe cuándo se eliminará el nodo DOM, y si está causando una fuga, supongo que esto significa que está utilizando otra biblioteca junto con jQuery. Esa no es una buena idea por esta misma razón.

Debe asegurarse de que jQuery elimine los elementos afectados por jQuery. También hay algunos datos almacenados en $.cache que no estableció explícitamente. Esto significa que todos los elementos se deben eliminar con jQuery, en lugar de solo aquellos que piensan que pueden tener datos.


"¿Cuál es el propósito de $.cache en jQuery?"

Para asociar los controladores y otros datos con los elementos. El enlace entre los datos y los elementos es básicamente un número de serie almacenado en una propiedad expando en el elemento.

Si elimina el elemento sin jQuery, los datos asociados en $.cache quedan huérfanos.

El objetivo de este enfoque era evitar posibles fugas. Lamentablemente, crea fugas más graves.

+0

1. Si la relación entre el elemento y los controladores se mantiene a través de un número de serie (y si el manejador no se refiere al elemento), no veo una razón por la cual las entradas .cache deberían conducir a la memoria fuga. Por alguna razón, no sé qué tan justificable es, la entrada de la memoria caché se refiere al elemento. Tengo curiosidad por saber por qué se requiere la referencia al elemento. 2. No conozco los casos en que la expansión de un elemento no puede contener referencias a objetos (manejadores) directamente. Si expando puede contener referencias, no veo la necesidad de una estructura paralela como .cache para contener referencias. – user968903

+0

@ user968903: 1. Solo provocan fugas si no utiliza los métodos de jQuery que eliminan la entrada relacionada '$ .cache' al eliminar el elemento. El número de serie es la única conexión entre los dos, por lo que si el elemento con el número '123' se elimina, pero jQuery no elimina la entrada' 123' en '$ .cache', entonces esa entrada ahora se refiere a los datos que ya no están disponibles. tiene un elemento correspondiente, y nunca será limpiado. La justificación eran posibles pérdidas de memoria que existen principalmente en IE6 y tal vez en IE7. Ahora que esos navegadores casi se han ido, no sé si este enfoque es bueno. –

+0

@ user968903: 2. Creo que los navegadores modernos generalmente limpian los elementos cuando se eliminan, por lo que probablemente ya no sea un problema. Creo que fue principalmente IE6/7 que tenía problemas. Creo que todavía puede haber pérdidas potenciales de memoria con respecto a los cierres, donde un elemento tiene un controlador que tiene en su alcance variable una referencia circular a sí mismo, pero no estoy seguro si ese es un problema hoy o no. Veré lo que puedo encontrar. –

5

Me encontré en una situación similar donde Knockout se utiliza para agregar y eliminar árboles dom del documento. Sin embargo, jquery se usa para adjuntar detectores de eventos a estos árboles dom. Cuando el knockout elimina elementos dom del documento, los oyentes no se desenlazan, por lo que el árbol dom no es elegible para la recolección de basura. Hemos agregado una función de limpieza que rastrea a través de jquery $ .cache cada vez que cambia el hash y encuentra incluso controladores que están vinculados a árboles dom que no están en el documento. A continuación, desvincula a los oyentes para que el árbol dom sea elegible para la recolección de basura y arregle la mayoría de las filtraciones que estamos viendo, es decir, un viaje de ida y vuelta de la aplicación utilizada para filtrar 13MB ahora filtra solo 3MB con estos cambios en su lugar.

for (var i in $.cache) { 
      if ($.cache.hasOwnProperty(i)) { 

       if ($.cache[i].handle && $.cache[i].handle.elem && document !== $.cache[i].handle.elem && !jQuery.contains(document, $.cache[i].handle.elem)) { 
        //we have an event handler pointing to a detached dom element! 
        //this is a memory leak as this detached dom element cannot be garbage collected until 
        //all references to it are removed. So lets delete the event handler to get memory back! 
        var orphan = $($.cache[i].handle.elem); 
        $('body').append(orphan); 
        orphan.off(); 
        orphan.remove(); 
        orphan = null; 
       } 
      } 
     } 
+1

Parece que esto es el resultado de un error en la eliminación 3.0.0. Cuando actualicé a 3.1.0, la pérdida de memoria desapareció sin la necesidad del código anterior. – Troup

Cuestiones relacionadas