2011-08-25 8 views
13

Pracuję nad dużą aplikacją dla firm z dużą ilością JavaScript. Wystarczająco dużo, że nie będę w stanie przejść i naprawić wszystkich małych okrągłych odnośników, które powstały w ciągu ostatnich 5 lat rozwoju. Podczas badania rozwiązań natknąłem tego małego jQuery hack/poprawki:wycieki jQuery rozwiązane, ale dlaczego?

http://kossovsky.net/index.php/2009/07/ie-memory-leak-jquery-garbage-collector/

i postanowił spróbować. O dziwo, działa! sIEVE nie wykazuje przecieków w miejscach, w których wcześniej je zidentyfikowałem, a zadanie iexplore utrzymuje łatwiejszy w zarządzaniu obszar pamięci.

Moje pytanie brzmi, dlaczego to działa? jQuery.remove wywołania .removeChild, które powinny pozbyć się elementu, ale najwyraźniej nie. Zamiast tego łata dołącza element docelowy do nowego elementu div odśmiecacza, który następnie kasuje. Dlaczego metoda usuwania poprawki całkowicie zwalnia pamięć, ale funkcja usuwania jQuery nie działa? Mam nadzieję, że zrozumiem, dlaczego to działa, aby ewentualnie poprawić rozwiązanie, zanim sprawdzę to w większej aplikacji.

Odpowiedz

12

To jest metoda .remove w bieżącym wydaniu jQuery (1.6.2). Zauważ, że wymaga to .cleanData:

// keepData is for internal use only--do not document 
    remove: function(selector, keepData) { 
     for (var i = 0, elem; (elem = this[i]) != null; i++) { 
      if (!selector || jQuery.filter(selector, [ elem ]).length) { 
       if (!keepData && elem.nodeType === 1) { 
        jQuery.cleanData(elem.getElementsByTagName("*")); 
        jQuery.cleanData([ elem ]); 
       } 

       if (elem.parentNode) { 
        elem.parentNode.removeChild(elem); 
       } 
      } 
     } 

     return this; 
    }, 

i metoda .cleanData której połączeń, które wymienia wiele biletów i rzekomo zapobiega straszne przeciek (wg jednego z komentarzy):

cleanData: function(elems) { 
     var data, id, cache = jQuery.cache, internalKey = jQuery.expando, special = jQuery.event.special, 
      deleteExpando = jQuery.support.deleteExpando; 

     for (var i = 0, elem; (elem = elems[i]) != null; i++) { 
      if (elem.nodeName && jQuery.noData[elem.nodeName.toLowerCase()]) { 
       continue; 
      } 

      id = elem[ jQuery.expando ]; 

      if (id) { 
       data = cache[ id ] && cache[ id ][ internalKey ]; 

       if (data && data.events) { 
        for (var type in data.events) { 
         if (special[ type ]) { 
          jQuery.event.remove(elem, type); 

         // This is a shortcut to avoid jQuery.event.remove's overhead 
         } else { 
          jQuery.removeEvent(elem, type, data.handle); 
         } 
        } 

        // Null the DOM reference to avoid IE6/7/8 leak (#7054) 
        if (data.handle) { 
         data.handle.elem = null; 
        } 
       } 

       if (deleteExpando) { 
        delete elem[ jQuery.expando ]; 

       } else if (elem.removeAttribute) { 
        elem.removeAttribute(jQuery.expando); 
       } 

       delete cache[ id ]; 
      } 
     } 
    } 

A tutaj jest bilet wymieniony w komentarzu. Najwyraźniej zostało to naprawione osiem miesięcy temu:

http://bugs.jquery.com/ticket/7054#comment:10

Według Dave'a Methvin rozwiązaniem wydaje się być Upewnić się, że DOM elementem ref w obsługi zdarzeń jest usuwany przez cleanData aby uniknąć IE6/7/8 wyciek pamięci.

Innymi słowy, należy ustawić odwołania do elementów DOM w ramach obsługi zdarzeń do null inaczej niesamowite przeglądarek, bez wymieniania żadnych nazwisk kaszel IE kaszel nastąpi wyciek pamięci.

discardElement (z linka) wstawia element do pojemnika, a następnie opróżnia kontener, tym samym unieważnia wszelkie odniesienia do tego elementu.

Mając to na uwadze, proponuję uaktualnienie jQuery. Artykuł, o którym mówisz, pochodzi z 2009 roku, a dwa lata to w przybliżeniu czterysta miliardów osobogodzin czasu rozwoju jQuery.

Wreszcie, tutaj jest kilka ciekawych (i absurdalnie długie) odczyt na wzorcach przeciek w programie Internet Explorer:

+0

Niestety nie mogę rozsądnie przejść przez cały kodzie szuka obsługi zdarzeń do wartości null. Właśnie dlatego intryguje mnie to hackowe rozwiązanie. O ile udowodniono, że jest to coś ze srebrnej kuli, która nie wymaga ręcznego ustawiania procedur obsługi na wartość zerową. – JPRO

+0

@JPRO - nie obsługuje zdarzeń, elementów DOM w modułach obsługi zdarzeń, i nie musisz tego robić, jeśli chcesz zaktualizować jQuery do nowszej wersji. – karim79

+0

Z pewnością zły kod był głównym czynnikiem przyczyniającym się do tego problemu i mogłem to wszystko przeanalizować i poprawić, ale zajęłoby to znacznie więcej czasu, niż przeznaczałem na to zadanie. Aktualnie używamy jQuery 1.6.2. To powiedziawszy, myślę, że odpowiedziałeś na pytanie, dlaczego to działa (doszedłem do tego samego wniosku, ale chciałem trochę więcej informacji). Dzięki za informację! – JPRO

1

Zamierzam teoretyzować, że jest podobny do zbierania śmieci .net, ponieważ opiera się na Przypiętych obiektach w stercie.

Program IE traktuje obiekt macierzysty usuniętego obiektu jak pinezkę i nie usuwa poprawnie usuniętego obiektu.

Czynność przeniesienia usuniętego elementu do wygenerowanego pojemnika gc polega zasadniczo na usunięciu szpilki, ponieważ IE wie, że nic nie polega na tym pojemniku.

W każdym razie to moje odczucie.

Powiązane problemy