2010-09-24 17 views
45

Mój kod JavaSript buduje listę elementów LI. Kiedy aktualizuję listę, zużycie pamięci rośnie i nigdy nie spada. Przetestowałem w sIEve i pokazuje, że przeglądarka przechowuje wszystkie elementy, które miały zostać usunięte przez komendy jQuery $.remove() lub $.empty.Jak usunąć elementy DOM bez wycieków pamięci?

Co należy zrobić, aby usunąć węzły DOM bez wycieku pamięci?

Zobacz kod my other question.

Odpowiedz

8

Czy usunąłeś jakiekolwiek detektory zdarzeń? To can cause memory leaks.

+0

I jeszcze zrobić dla każdego elementu $ (this) .unbind() html ("") usunąć(); – podeig

+2

Myślałem, że jQuery automatycznie usuwa programy obsługi zdarzeń, gdy robisz element.remove(), nie? – jayarjo

+0

@jayarjo - to ma – vsync

43

DOM zachowuje wszystkie węzły DOM, nawet jeśli zostały one usunięte z drzewa DOM, jedynym sposobem na usunięcie tych węzłów jest odświeżenie strony (jeśli umieścisz listę w ramce iframe, odświeżenie nie będzie być wyczuwalny)

w przeciwnym razie, można poczekać problemu dostać się na tyle złe, że kolektor przeglądarek śmieci jest zmuszony do działania (rozmowy setki megabajtów niewykorzystanych węzłów tutaj)

Najlepszą praktyką jest wykorzystanie węzłów.

EDIT: Spróbuj tego:

var garbageBin; 
window.onload = function() 
    { 
    if (typeof(garbageBin) === 'undefined') 
     { 
     //Here we are creating a 'garbage bin' object to temporarily 
     //store elements that are to be discarded 
     garbageBin = document.createElement('div'); 
     garbageBin.style.display = 'none'; //Make sure it is not displayed 
     document.body.appendChild(garbageBin); 
     } 
    function discardElement(element) 
     { 
     //The way this works is due to the phenomenon whereby child nodes 
     //of an object with it's innerHTML emptied are removed from memory 

     //Move the element to the garbage bin element 
     garbageBin.appendChild(element); 
     //Empty the garbage bin 
     garbageBin.innerHTML = ""; 
     } 
    } 

Aby użyć go w kontekście, byś zrobił to tak:

discardElement(this); 
+9

Nie wiedziałem o "DOM zachowuje wszystkie węzły DOM, nawet jeśli zostały one usunięte z drzewa DOM" Czy masz na myśli funkcję $ .remove() nic nie robić? – podeig

+0

Ile MegaBite należy użyć do uruchomienia garbage collector. Myślę, że 150 Mb musi wystarczyć. Ale to nie działa dla mnie. – podeig

+0

Edytowane, spróbuj podać kod. –

2

Poniższy kod nie wycieka na moim IE7 i inne przeglądarki:

<html> 
<head></head> 
<body> 
    <a href="javascript:" onclick="addRemove(this)">add</a> 
    <ul></ul> 
    <script> 
     function addRemove(a) { 
      var ul = document.getElementsByTagName('UL')[0], 
       li, i = 20000; 
      if (a.innerHTML === 'add') { 
       while (i--) { 
        li = document.createElement('LI'); 
        ul.appendChild(li); 
        li.innerHTML = i; 
        li.onclick = function() { 
         alert(this.innerHTML); 
        }; 
       } 
       a.innerHTML = 'remove'; 
      } else { 
       while (ul.firstChild) { 
        ul.removeChild(ul.firstChild); 
       } 
       a.innerHTML = 'add'; 
      } 
     } 
    </script> 
    </body> 
</html> 

Być może możesz spróbować dostrzec różnicę z twoim kodem.
Wiem, że IE przecieka znacznie mniej, gdy wstawiasz najpierw węzeł w DOM, zanim coś z nim zrobisz, np. Dołączając do niego zdarzenia lub wypełniając jego właściwość innerHTML.

13

To jest bardziej niż FYI niż faktyczna odpowiedź, ale jest również całkiem interesująca.

Z W3C DOM rdzenia opisie (http://www.w3.org/TR/DOM-Level-2-Core/core.html):

Główni DOM API są zaprojektowane kompatybilność z szeroką gamą języków, w tym z językami skryptowymi ogólnego użytkownika oraz z trudniejszymi językami używanymi głównie przez profesjonalnych programistów. W związku z tym interfejsy DOM API muszą działać w oparciu o różnorodne filozofie zarządzania pamięcią, od powiązań językowych, które w żaden sposób nie ujawniają zarządzania pamięcią użytkownikowi, poprzez te (w szczególności Java), które zapewniają jawne konstruktory, ale automatycznie udostępniają mechanizm automatycznego czyszczenia pamięci. odzyskaj nieużywaną pamięć, do tych (zwłaszcza C/C++), które zazwyczaj wymagają od programisty jawnego przydzielenia pamięci obiektu, śledzenia miejsca jej użycia i jawnego uwolnienia go do ponownego użycia. Aby zapewnić spójny interfejs API dla tych platform, DOM nie zajmuje się w ogóle kwestiami zarządzania pamięcią, ale pozostawia je do wdrożenia. Żadne z jawnych powiązań językowych zdefiniowanych przez DOM API (dla ECMAScript i Java) nie wymaga żadnych metod zarządzania pamięcią, ale powiązania DOM dla innych języków (szczególnie C lub C++) mogą wymagać takiej obsługi. Te rozszerzenia będą obowiązkiem tych, którzy dostosowują DOM API do konkretnego języka, a nie do Grupy Roboczej DOM.

Innymi słowy: zarządzanie pamięcią jest pozostawione do implementacji specyfikacji DOM w różnych językach. Będziesz musiał zajrzeć do dokumentacji implementacji DOM w javascript, aby znaleźć jakąkolwiek metodę usunięcia obiektu DOM z pamięci, która nie jest hackerem. (Jest to jednak bardzo niewiele informacji na stronie MDC na ten temat.)


Jako notatkę na jQuery#remove i jQuery#empty: z tego co mogę powiedzieć, żadna z tych metod nie robi niczego innego niż usunięcie Object s od DOM node s lub usuwanie DOM node s z document. Usuwają tylko To oczywiście nie oznacza, że ​​nie ma pamięci przydzielonej do tych obiektów (nawet jeśli nie są one już w stanie document).

Edit: Powyższy fragment był zbędny, ponieważ oczywiście jQuery nie może czynić cuda i prace wokół realizacji DOM zastosowanego przeglądarce.

+1

from jQuery .remove() API: "... Oprócz samych elementów, wszystkie powiązane zdarzenia i dane jQuery powiązane z elementami są usuwane. Aby usunąć elementy bez usuwania danych i zdarzeń, użyj zamiast tego polecenia .detach()." – vsync

+0

Powiedziałeś, że" z tego, co mogę powiedzieć, żadna z tych metod nie robi niczego innego niż usuwanie obiektów z węzłów DOM lub usuwanie węzłów DOM z dokumentu ".. więc zacytowałem z API, że robi to więcej niż to. wszystkie związane zdarzenia – vsync

+1

Kontekstem była alokacja pamięci, ale no cóż, tam zaatakowałem przejście na 'jQuery'. – FK82

Powiązane problemy