2010-11-12 25 views
6

Po prostu spotkałem się z klientem, który ma ogromne problemy z wyciekiem pamięci w swojej aplikacji internetowej Ajax. Więc postanowiłem utworzyć następujący testcase wykazać problem:Dodanie elementów DOM z jquery append() wydaje się przeciekać pamięć?

Użyłem kroplówka/Sito do profilowania pamięci w poniższym przykładzie (http://home.orange.nl/jsrosman/)

The Przypadek jest prosty: Mam następujący javascript:

<html> 
    <head>  
    <script type="text/javascript" src="http://code.jquery.com/jquery-1.4.4.min.js"> 
</script>  
</head>  
<script type="text/javascript"> 

    var lihtml = "<li class='green'>this is a test text</li>"; 

    function populatelist() { 
     for (var i = 0; i < 10000; i++) { 
      $('#listparent').append(lihtml); 
     }  
    }  

    function clearlist() { 
     $('#listparent').empty(); 
     if (typeof (CollectGarbage) == "function") { 
      alert('gc'); 
      CollectGarbage(); 
     }  
    } 


    /* Alternative clearlist with Remove instead of Empty(), still leaks */ 
    function clearlist() { 
     /* test remove the parent itself instead of empty below */ 
     $('#listparent').remove(); 
     $('body').append("<ul id='listparent'>");   
     //$('#listparent').empty(); 
     if (typeof (CollectGarbage) == "function") { 
      alert('gc'); 
      CollectGarbage(); 
     } 
    } 

    /* Edit!, this is the most effective way to release memory so far */ 
    function clearlist() { 
    $('#listparent').html(""); 
    if (typeof (CollectGarbage) == "function") { 
     alert('gc'); 
     CollectGarbage(); 
    } 
} 
</html> 
</script> 

<body> 
    <button onclick="javascript:populatelist()">Populate list</button> 
    <button onclick="javascript:clearlist()">Clear list</button> 
    <ul id="listparent"> 
     <li>kjjk</li> 
    </ul>  
</body> 

</html> 

Każde kliknięcie na liście wypełnia dołącza 10000 elementów li (reprezentowanych jako tekst). Lista jawna wywołuje jQuery puste(), które rzekomo powinno wyczyścić poddrzewo DOM i sprawić, by kwalifikowało się ono do GC.

Tak więc uruchamiam tę sprawę w SIEVE i za każdym razem, gdy dołączam nowe elementy, zużycie pamięci wzrasta, nigdy nie widziałem, aby to było zbędne lub wolna pamięć. Nawet wtedy, gdy użycie pamięci RAM osiąga 1,5 GB i mimo, że próbuję wywoływać GC jawnie dla IE.

To jest ten sam sympton, który widziałem u klienta, który używał Ajax Jquery dla danych listy zamiast mojej statycznej zawartości obv.

Czy tworzę DOM w niewłaściwy sposób? Czy ktokolwiek może mi powiedzieć, dlaczego nie zbiera śmieci, nie widzę żadnych innych odniesień do elementów DOM, dlaczego nie powinny być zbierane śmieci. Kolejne dziwne zachowanie polega na tym, że czasami użycie pamięci SIEve wzrasta nawet wtedy, gdy klikam pustą listę (gdy wywoływana jest metoda jquery empty())?

Jeśli ktokolwiek ma dane, byłbym BARDZO szczęśliwy.

AKTUALIZACJA, próbowałem za pomocą $ ('# listparent'). Html ("") zamiast, który wydaje się wydawać DOM poprawnie, przynajmniej jest wydany w sIEve. Sądzę, że to najlepsze rozwiązanie, chociaż nie mam żadnego wyjaśnienia, dlaczego remove() i empty() nie działają. Może pracują tylko dla statycznie dodanych elementów?

+0

tylko ciekaw, czy próbowałeś to w wielu przeglądarkach? – Prescott

+0

Żadne sIEve działa tylko w IE, nie próbowałem FFX, głównie dlatego, że IE jest jedyną używaną przeglądarką przez użytkowników w tym systemie. – user408346

+0

Właściwie $ ('# listparent').html (""); działa znacznie lepiej niż puste() i remove() i wydaje się wypuścić cały DOM. Zaniemówiłam. – user408346

Odpowiedz

1

tak można zrób ogromny postęp robi smthg jak tak

var lihtml = "<li class='green'>this is a test text</li>", 
    listring = ""; 

function populatelist() { 
     for (var i = 0; i < 10000; i++) { 
      listring += lihtml; 
     }  

     $('#listparent').append(listring); 

    }  
... 

ograniczenie dostępu DOM tak mało jak to możliwe.

Różnica polega na tym, że tworzysz jeden pojedynczy załącznik zamiast 10 tysięcy dołączeń. Zawsze musisz unikać manipulacji DOM wewnątrz cykli

Edytuj: zamiast pustego() twój ul próbowałeś usunąć() ul, a następnie nagle go utworzyć ponownie?

+0

To jest dobra sugestia i spróbowałem, problem wciąż pozostaje, nadal jest nieszczelny i pusty() nie wydaje się uwolnić DOM. Poważnie zaczyna tracić wiarę w jquery. – user408346

+0

Edytowałem moją odpowiedź –

+1

Próbowałem usunąć(), nadal przecieki, ale może nieco mniej niż puste(), które wydaje się zwiększać pamięć, a nie zwolnienia. Co jest naprawdę dziwne, to $ ("# listparent"). Html (""); działa i wypuszcza całą pamięć DOM i RAM?!? – user408346

1

Proponuję dodanie do napisu HTML i następnie dodanie go do DOM:

function populatelist() { 
    for (var i = 0; i < 10000; i++) { 
     //$('#listparent').append(lihtml); 
     lihtml += "<li class='green'>this is a test text</li>"; 
    }  
}  
populateList(); 
$('#listparent').append(lihtml); 
+0

Tak samo jak poniżej, dobra sugestia, ale wyciek pozostaje. – user408346

0
$('#listparent').html(""); 

prace gdzie ani empty() lub usunąć() zrobił. Chciałbym wiedzieć dlaczego. Myślę, że to rozwiązanie.

/* To jest najbardziej skutecznym sposobem, aby zwolnić pamięć tak daleko */

function clearlist() { 
    $('#listparent').html(""); 
    if (typeof (CollectGarbage) == "function") { 
     alert('gc'); 
     CollectGarbage(); 
    } 
Powiązane problemy