2010-11-12 26 views
6

Appena incontrato un cliente che ha enormi problemi di perdita di memoria nella sua app web Ajax. Così ho deciso di creare la seguente testcase per dimostrare il problema:L'aggiunta di elementi DOM con jquery append() sembra perdere memoria?

ho usato a goccia/Sieve per il profiling di memoria nell'esempio che segue (http://home.orange.nl/jsrosman/)

Il caso è semplice: ho il seguente 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> 

Ogni cliccare sul elenco popola aggiunge i 10000 elementi li (rappresentato come testo). Clearlist chiama jquery empty() che presumibilmente dovrebbe cancellare la sottostruttura DOM e renderla idonea per GC.

Così eseguo questo caso in SIEVOLE e per ogni volta che aggiungo nuovi elementi l'utilizzo della memoria aumenta, non l'ho mai visto raccolta di dati inutili o memoria libera. Neanche quando l'utilizzo della RAM raggiunge 1,5 GB e anche se provo a chiamare GC esplicitamente per IE.

Questo è lo stesso sympton che ho visto dal cliente che ha utilizzato Jquery Ajax per i dati dell'elenco invece del mio contenuto statico obv.

Sto creando il DOM nel modo sbagliato? Qualcuno può dirmi perché non si tratta di garbage collection, non riesco a vedere nessun altro riferimento agli elementi DOM sul motivo per cui non dovrebbero essere raccolti. Un altro strano comportamento è che a volte in uso la memoria aumenta anche quando faccio clic sulla lista vuota (quando viene chiamato il metodo jquery empty())?

Se qualcuno ha inserito sarei MOLTO felice.

UPDATE, ho provato a utilizzare $ ('# listparent'). Html ("") invece che sembra rilasciare correttamente il DOM, almeno è stato rilasciato in sIEve. Immagino che sia la soluzione migliore finora, anche se non ho alcuna spiegazione sul perché remove() e empty() non sembrano funzionare. Forse funzionano solo per elementi aggiunti staticamente?

+0

solo curioso, hai provato questo in più browser? – Prescott

+0

No sIEVE funziona solo in IE, non ho provato FFX, principalmente perché IE è l'unico browser utilizzato dagli utenti in questo sistema. – user408346

+0

In realtà $ ('# listparent').html (""); funziona molto meglio di entrambi empty() e remove() e sembra rilasciare l'intero DOM. Sono senza parole – user408346

risposta

1

sì, si potrebbe fare un miglioramento enorme facendo smthg in questo modo

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); 

    }  
... 

limitare l'accesso DOM il meno possibile.

La differenza è che si effettua 1 singola aggiunta anziché 10 migliaia di allegati. È sempre necessario evitare la manipolazione DOM all'interno dei cicli

Modifica: invece di vuoto() il tuo ul hai provato a rimuovere() l'ul e quindi improvvisamente lo ricrea?

+0

Questo è un buon suggerimento e l'ho provato, il problema rimane comunque, sta ancora perdendo e vuoto() non sembra liberare il DOM. Inizia seriamente a perdere fiducia in jQuery. – user408346

+0

Ho modificato la mia risposta –

+1

Ho provato remove(), perde ancora ma forse leggermente meno di empty() che sembra aumentare la memoria piuttosto che rilasciare. Ciò che è veramente strano è che $ ('# listparent'). Html (""); fa il trucco e rilascia l'intero DOM e la memoria RAM?!? – user408346

1

Suggerisco aggiungendo alla stringa HTML e quindi aggiungendolo al 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

Lo stesso di seguito, buon suggerimento ma la perdita rimane. – user408346

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

opere in cui né vuota() o rimuovere() fatto. Vorrei sapere il perché. Immagino sia una soluzione però.

/* Questo è il modo più efficace per liberare la memoria finora */

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