2010-01-04 10 views
24

Von was ich von einer nicht allzu fernen Vergangenheit erinnere, erlitt Javascript Dolmetscher von Speicher undicht Probleme, wenn mit kreisförmigen Referenzen konfrontiert.Javascript, Zirkelreferenzen und Speicherlecks

Ist es immer noch in den neuesten Browsern? (ZB Chrome, FF 3.5 usw.)

Antwort

28

Die überwiegende Mehrheit von Lecks wir Mit JavaScript sprechen Sie speziell in IE6-7, wenn Sie eine Referenzschleife zwischen JavaScript-Objekten und Host-Objekten wie DOM-Knoten erstellen.

In IE6 ist dies besonders schädlich, weil Sie den Speicher nicht zurückbekommen, wenn Sie die Seite verlassen; Es ist weg, bis Sie den Browser verlassen. Beim IE7-Löschen gibt die Seite jetzt den Speicher zurück, aber Sie können immer noch Schwierigkeiten haben, wenn Sie eine lang laufende Anwendung haben. IE8 löst das meiste dieses Problems richtig, indem die DOM-Knoten in native JavaScript-Objekte anstelle von Host-Objekten umgewandelt werden. (Sie könnten immer noch die Lecks in IE8 auslösen, indem Sie andere nicht-native Objekte wie ActiveX-Objekte in einer Referenzschleife einbinden.)

Es wird sicherlich noch kleine obskure Speicherlecks an zufälligen Orten für alle Browser lauern, besonders in ältere Versionen. Aber es gibt keine einfache Möglichkeit, sie zu kategorisieren und zu vermeiden, wie bei der IE Refloop-Problematik.

+1

+1: lange für diese perl der Weisheit gesucht. –

+0

@Marco Demaio Hmm, diese http://ecmascript.stchur.com/blogcode/ie_innerhtml_memleak/leak.html leckt immer noch in IE9 entweder Standards oder Macken Modus (Win7 64bit), Seien Sie sicher, Prozess Explorer bei der Überwachung der privaten Bytes zu verwenden .. seufz .. –

+0

@AlexanderN: eigentlich auf IE8 WXP die Seite, die Sie vorgeschlagen, leckt nicht. Ich verwende den einfachen "Windows Task-Manager" (Registerkarte "Leistung"), um zu sehen, ob die Seite undicht ist. In einem solchen Fall würde sich die "PF-Nutzung" mehr und mehr erhöhen. –

17

Um zu bobince Antwort hinzuzufügen, habe ich einige Tests mit IE8.

Ich versuchte fast alle bereitgestellten Beispiele bei http://www.javascriptkit.com/javatutors/closuresleak/index.shtml

Keiner von ihnen ist undicht Speicher mehr (zumindest nicht in einer wahrnehmbaren Weise), außer dem Beispiel, das Kind-Knoten mit Ereignissen entfernt noch an ihnen.

Diese Art von Beispiel, ich denke, es ist besser erklärt von Douglas Crockford in seinem questest2.

Diese noch Speicher auf IE8 und es ist ziemlich einfach zu testen, indem Sie einfach the test script und Windows Task Manager - Performance - PF Usage. Sie werden feststellen, dass die PF-Auslastung um fast 1 MB pro Schleife (sehr schnell) ansteigt.

Aber in IE8 wird der Speicher auf Seite Entladen freigegeben (wie zu einer neuen Seite navigiert oder die gleiche Seite Nachladen) und natürlich auch total beim Schließen des Browsers.

Damit ein Endanwender diese Speicherlecks auf IE8 (als reduzierte Systerm-Performances) wahrnimmt, muss er lange auf der gleichen Seite bleiben, was in den heutigen Tagen aber häufig mit AJAX passieren kann, aber Diese Seite muss auch Hunderte von Childnodes Entfernung von Elementen mit Ereignis an sie.

Douglas Crockford Test stressing der Browser mit 10000 Knoten hinzugefügt und dann entfernt, das ist hervorragend für das Zeigen des Problems, aber im wirklichen Leben hatte ich nie eine Seite, die mehr als 10 Elemente entfernt.INMHO ist es normalerweise schneller, display: none zu verwenden, anstatt einen ganzen Satz von Knoten zu entfernen, deshalb verwende ich removeChild nicht so viel.


Denn wer im IE8 Speicherleck mehr interessiert sein könnte oben erklärt wurde, habe ich einen weiteren Test, und es scheint mem Lecks gar nicht in IE8 angezeigt, wenn innerHTML anstelle von appendChild/removeChild mit hinzufügen/Entfernen Sie untergeordnete Elemente mit angehängten Ereignissen. So scheinbar Douglas Crockford purge function (vorgeschlagen von ihm Speicherlecks im Internet Explorer zu verhindern) ist notwendig, nicht mehr in IE8 zumindest bei der Verwendung von innerHTML ...

(EDITED dank 4esn0k Kommentar unten) ... außerdem Douglas Crockford purge function funktioniert überhaupt nicht auf IE8, in seinem Code var a = d.attributes gibt keine onclick Attribute (oder andere onevent Attribute), die zur Laufzeit auf IE8 hinzugefügt wurden (sie sind auf IE7 zurückgegeben).

Douglas Crockford sagt:

"Die Reinigungsfunktion vor dem Entfernen jedes Element aufgerufen werden soll, entweder durch die removeChild Methode oder durch die innerHTML- Eigenschaft festlegen."

biete ich hier den Code für den 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

Ist "Douglas Crockford Purge Function" hier hilfreich für IE 8? Scheint, seit IE8 (im IE8-Modus, nicht kompatibler Modus) "on.click" ist nicht auf "onclick" -Attribut zugeordnet, so kann Purge "onclick" in Attributen nicht finden. Habe ich recht? – 4esn0k

+0

@ 4esn0k: Entschuldigung, aber ich bin mir nicht sicher, was du meinst. –

+1

var s = document.createElement ('div'); s.onclick = function() {}; var a = s.attributes; für (var i = 0; i 4esn0k