2010-01-04 6 views

risposta

28

La stragrande maggioranza delle perdite che parlare di JavaScript è specificamente in IE6-7 quando si crea un ciclo di riferimento tra oggetti JavaScript e oggetti host come i nodi DOM.

In IE6 questo è particolarmente dannoso in quanto non si recupera la memoria quando si esce dalla pagina; è andato fino a quando non esci dal browser. In IE7, la cancellazione della pagina ora restituisce la memoria, ma è ancora possibile avere difficoltà quando si dispone di un'applicazione a esecuzione prolungata. IE8 risolve correttamente la maggior parte di questo problema trasformando i nodi DOM in oggetti JavaScript nativi anziché in oggetti host. (Potresti ancora attivare le perdite in IE8 includendo altri oggetti non nativi come oggetti ActiveX in un ciclo di riferimento.)

Ci saranno sicuramente piccole oscure perdite di memoria in agguato in luoghi casuali per tutti i browser, specialmente in versioni precedenti. Ma non c'è un modo per categorizzare facilmente ed evitarli come con il problema del rilascio di IE.

+1

+1: cercato a lungo per questo perl di saggezza. –

+0

@Marco Demaio Hmm, questo http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/leak.html perde ancora in IE9 in modalità standard o quirk (win7 64 bit), assicurati di utilizzare Process Explorer quando monitora i byte privati .. sigh .. –

+0

@AlexanderN: in realtà su IE8 WXP la pagina che hai suggerito non perde. Io uso il semplice "Task Manager di Windows" (scheda "Prestazioni") per vedere se la pagina perde, in tal caso si vedrebbe "L'utilizzo di PF" aumentare sempre di più. –

17

Per aggiungere al bobince risposta, ho fatto alcuni test con IE8.

Ho provato quasi tutti gli esempi forniti da http://www.javascriptkit.com/javatutors/closuresleak/index.shtml

Nessuno di loro è che perde la memoria più (almeno non in modo percepibile), salvo l'esempio che rimuove nodi figlio con eventi ancora ad essi connessi.

Questo tipo di esempio penso che sia meglio spiegato da Douglas Crockford nella sua coda2.

Questo ancora perdite di memoria su IE8 ed è abbastanza facile verificare semplicemente eseguendo the test script e guardando Task Manager di Windows - Prestazioni - PF di utilizzo. Vedrete che PF Usage aumenta di quasi 1 MB per loop (molto veloce).

Ma in IE8 memoria viene rilasciato a pagina scarico (come navigazione verso una nuova pagina o ricaricare la stessa pagina) e ovviamente anche se completamente chiusura del browser.

Quindi, per consentire all'utente finale di percepire questa perdita di memoria su IE8 (come prestazioni systerm ridotte), ha bisogno di rimanere sulla stessa pagina per un lungo periodo di tempo, che in alcuni giorni può accadere spesso con AJAX, ma questa pagina deve anche fare centinaia di rimozione di elementi childs con elementi collegati a loro.

prova Douglas Crockford è sottolineando il browser con 10000 nodi aggiunti e poi rimosso, che è eccellente per che vi mostra il problema, ma nella vita reale non ho mai avuto una pagina che ha rimosso più di 10 elementi.INMHO di solito è più veloce usare display: none invece di rimuovere un intero set di nodi, ecco perché non uso più tanto lo removeChild.


Perché chi potrebbe essere più interessato alla perdita di memoria IE8 spiegato sopra, ho fatto un altro test e sembra perdite mem non appaiono affatto in IE8 quando si utilizza innerHTML al posto di appendChild/removeChild per aggiungere/rimuovi elementi figlio con eventi collegati. Quindi, a quanto pare Douglas Crockford purge function (suggerito da lui per evitare perdite di memoria in IE) non è più necessario in IE8, almeno quando si utilizza innerHTML ...

(CURATE grazie a 4esn0k commento qui sotto) ... inoltre Douglas Crockford purge function non funziona affatto su IE8, nel suo codice var a = d.attributes restituisce NO onclick attributi (o qualsiasi altro onevent attributi) che sono stati aggiunti in fase di esecuzione su IE8 (vengono restituiti su IE7).

Douglas Crockford dice:

"La funzione di spurgo deve essere chiamata prima di rimuovere qualsiasi elemento, sia dal metodo removeChild, oppure impostando la struttura innerHTML."

che fornisco qui il codice per il test:

<body>  
    <p>queuetest2 similar to the one provided by Douglas Crockford 
    at http://www.crockford.com/javascript/memory/leak.html 
    <br>but this one adds/removes spans using innerHTML 
    instead of appendChild/removeChild.</p> 

    <div id="test"></div>  
    <script> 
     /* ORIGINAL queuetest2 CODE FROM DOUGLAS CROCKFORD IS HERE 
      http://www.crockford.com/javascript/memory/queuetest2.html */ 

     (function (limit, delay) 
     { 
      var n = 0; 
      var add = true; 

      function makeSpan(n) 
      { 
       var div = document.getElementById('test'); 
       //adding also an inline event to stress more the browser 
       div.innerHTML = "<span onmouseover=\"this.style.color = '#00ff00';\">" + n + "</span>"; 
       var s = div.getElementsByTagName('span')[0]; 
       s.onclick = function(e) 
       { 
        s.style.backgroundColor = 'red'; 
        alert(n); 
       }; 
       return s; 
      } 

      function process(n) 
      { 
       if(add)      
       s = makeSpan(n); 
       else 
       s.parentNode.innerHTML = ""; //removing span by clearing the div innerHTML 
       add = !add; 
      } 

      function loop() 
      { 
       if (n < limit) 
       { 
        process(n); 
        n += 1; 
        setTimeout(loop, delay); 
       } 
      } 

      loop(); 
     })(10000, 10); 

    </script> 
</body> 
+0

La "funzione di spurgo di Douglas Crockford" è utile per IE 8 qui? Sembra che da IE8 (in modalità IE8, modalità non compatibile) "s.onclick" non sia mappato all'attributo "onclick", quindi l'eliminazione non può trovare "onclick" negli attributi. Ho ragione? – 4esn0k

+0

@ 4esn0k: scusa ma non sono sicuro di cosa intendi. –

+1

var s = document.createElement ('div'); s.onclick = function() {}; var a = sattributes; per (var i = 0; i 4esn0k