Wie kann ich Speicherlecks beim Entfernen von Bildern im DOM verhindern?

Lesezeit: 7 Minuten

Benutzer-Avatar
andyuk

Da ist ein bekannter Fehler im Webkit dass beim Entfernen eines Bildes aus dem DOM der damit verbundene Speicher nicht freigegeben wird.

Dies ist ein Problem mit Single-Page-Apps, die oft Bilder laden.

Verschiedene Lösungsvorschläge sind:

Die ersten 3 Methoden funktionieren bei mir nicht. Der Hauptnachteil beim Recycling von Bildelementen besteht darin, dass viel Code geschrieben werden muss, um dies zu verwalten. Ich lade neues HTML über AJAX, das Bilder enthalten kann, daher kenne ich nicht unbedingt die Anzahl der Bilder, die geladen werden.

Gibt es andere Problemumgehungen, um dieses Problem zu beheben?

  • Ich glaube nicht, dass ein Bilderpool so viel Code wäre; und es kann problemlos eine beliebige Anzahl oder Bilder unterstützen.

    – Bergi

    13. Dezember 2012 um 11:42 Uhr

  • Und was ist falsch mit dem Entfernen src Attribut?

    – raina77ow

    13. Dezember 2012 um 11:42 Uhr

  • Abhängig davon, welche (und ob) Bibliothek Sie verwenden, können Sie die Funktion zum Entfernen von Knoten umschließen, um diesen Sonderfall beim Entfernen zu behandeln src zuerst, bevor Sie img selbst entfernen.

    – WTK

    13. Dezember 2012 um 12:04 Uhr

  • Habe gerade meine Frage aktualisiert – das Entfernen des src-Attributs funktioniert bei mir nicht.

    – andjuk

    13. Dezember 2012 um 12:08 Uhr

  • Wie können Sie die Anzahl der Bilder nicht kennen, wenn Sie den Image()-Konstruktor für jedes Bild manuell aufrufen (die Ursache des verknüpften Fehlers). Ich glaube nicht, dass Probleme beim Einfügen von HTML mit img-Tags von diesem Fehler abgedeckt werden.

    – dandavis

    28. Dezember 2013 um 7:31 Uhr


Benutzer-Avatar
Shiva Tumma

Ich habe 3 verschiedene Arten von Ansätzen verwendet …

Zuerst. Habe eine Reihe von Bildern hinzugefügt und die Garbage Collection dem Browser überlassen.
Geben Sie hier die Bildbeschreibung ein

Es wird definitiv Müll gesammelt, aber nach einer Weile wird sichergestellt, dass keine Notwendigkeit für die erstellten Bilder besteht.

Zweite. Verwendet ein data:URI-Muster für die src für Bilder.

var s = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";

for (var i = 0; i < 100; i++){
    var img = document.createElement("img");
    img.src = s;
document.getElementById("myList1").appendChild(img);
setTimeout(function(){img = null;}, 1000);
}

Geben Sie hier die Bildbeschreibung ein

Dies sah ähnlich aus, obwohl es für mich etwas besser war, als ich vor meinem Browser zusah und feststellte, dass weniger Speicher verwendet wurde und die Garbage Collection fast die gleiche wie oben war.

Dritte. Garbage Collection im Code durchgeführt.

var s = "data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAAAUAAAAFCAYAAACNbyblAAAAHElEQVQI12P4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg==";

for (var i = 0; i < 100; i++){
    var img = document.createElement("img");
    img.src = "https://stackoverflow.com/questions/13859041/dot.png";  // or the other, both mean the same here.
    img.src = s;
document.getElementById("myList1").appendChild(img);
setTimeout(function(){img = null;}, 1000);
}

Geben Sie hier die Bildbeschreibung ein

In dieser kurzen Testzeit war ich der Meinung, dass der letzte Ansatz besser funktionierte, da er den Speicherplatz fast sofort freigab, ohne abzuwarten, ob die referenzierten Bilder weiter benötigt werden.

Alles in allem, Sie verwenden die Garbage Collection besser selbst, wenn Sie unbedingt das Gefühl haben, dass etwas befreit werden muss.

  • Durch die Nutzung data:URI Sie verpassen das gesamte Browser-HTTP-Caching … in einer Produktionsanwendung wird dies sehr auffällig sein.

    – p3drosola

    3. Januar 2014 um 15:37 Uhr

  • Gutes Argument. Normalerweise lege ich sie alle hinein css oder js und cachen Sie diese Assets.

    – Shiva Tumma

    3. Januar 2014 um 15:42 Uhr


  • ja, aber es erscheint in dieser Anwendung, Bilder sind der Inhalt, also wird es nicht funktionieren.

    – p3drosola

    3. Januar 2014 um 15:43 Uhr

  • Wie kann nicht? Ich möchte Ihnen nicht widersprechen, aber wie kann dieser Ansatz überhaupt nicht funktionieren? setze ein js Datei, die alle enthält src Variablen und cachen Sie das. img1 ="fjsa;lfs=", img2="fjasdjfs="usw. Es sieht so aus, als ob es auch für diese Frage problemlos funktionieren kann.

    – Shiva Tumma

    3. Januar 2014 um 15:46 Uhr

  • @sivatumma Ich denke, was Ped meinte, war, dass Sie nicht alle Bilder vorher kennen würden. Stellen Sie sich zum Beispiel ein Szenario vor, in dem Sie Bilder in die anzuzeigende Anwendung hochladen. Sie können unmöglich den Dateinamen kennen, um ihn vorher in die JS-Datei einzufügen.

    – Kann ich nicht sagen

    7. Januar 2014 um 10:24 Uhr


Benutzer-Avatar
Paulscode

Ein einfacher Bilderpool sollte es Ihnen ermöglichen, img-Elemente zur Wiederverwendung zu recyceln. Da Sie im Voraus nicht wissen, wie viele Bilder es insgesamt geben wird, erweitern Sie einfach die Poolgröße nach Bedarf.

So etwas sollte funktionieren:

    function getImg( id, src, alt ) {
        var pool = document.getElementById( 'image_pool' );
        var img = ( pool.children.length > 0 ) ? pool.removeChild( pool.children[0] ) : document.createElement( 'img' );
        img.id = id;
        img.src = src;
        img.alt = alt;
        return img;
    }
    function recycleImg( id ) {
        var img = document.getElementById( id );
        document.getElementById( 'image_pool' ).appendChild( img.parentNode.removeChild( img ) );
    }

Platzieren Sie irgendwo auf Ihrer Seite einen versteckten “image_pool”-Container, um die recycelten Bilder zwischen der Verwendung zu verstecken:

<div id="image_pool" style="display:none;"></div>

Rufen Sie dann jedes Mal, wenn Sie ein neues img-Element benötigen, auf:

document.getElementById( 'some_element_id' ).appendChild( getImg( 'my_image_id', 'images/hello.gif', 'alt_text' ) );

Und wenn Sie damit fertig sind:

recycleImg( 'my_image_id' );

jQuery-Alternative

    function getImg( id, src, alt ) {
        var img;
        if( $("#image_pool").children().length > 0 ) {
            return $("#image_pool img:first-child").attr( { 'id': id, 'src': src, 'alt': alt } ).detach();
        }
        return $( "<img />'" ).attr( { 'id': id, 'src': src, 'alt': alt } );
    }
    function recycleImg( id ) {
        $( "#" + id ).detach().appendTo( $("#image_pool") );
    }

Wenn Sie ein neues img-Element benötigen:

getImg( 'my_image_id', 'images/hello.gif', 'alt_text' ).appendTo( $( "#some_element_id" ) );

(Recycling funktioniert wie oben)

  • Ich bin mir nicht sicher, aber das Trennen in JQuery zerstört tatsächlich den Knoten, und appendTo erstellt einen neuen Knoten im DOM. Es gibt also eigentlich gar kein Recycling.

    – Guillermo Gutierrez

    3. Januar 2014 um 14:29 Uhr

  • Interessant, ich müsste mir den Quellcode ansehen, um dies zu überprüfen. In jedem Fall füge ich hier eine Version hinzu, die keine jQuery-Funktionen verwendet, nur als Referenz.

    – Paulscode

    3. Januar 2014 um 14:34 Uhr

  • Habe die Frage hier gepostet: stackoverflow.com/questions/20905866/…

    – Guillermo Gutierrez

    3. Januar 2014 um 15:55 Uhr

  • Danke, dass Sie die Frage gestellt haben, @GuillermoGutiérrez Klingt so, als ob das Element sowohl in den Funktionen „distach()“ als auch „remove()“ erhalten bleibt, also sollte das Element im Fall meines obigen Codes wie beabsichtigt ordnungsgemäß recycelt werden.

    – Paulscode

    3. Januar 2014 um 16:32 Uhr

Benutzer-Avatar
Michael Galaxis

Versuchen Sie, das Javascript-DOM-Baumobjekt auf “null” zu setzen.

Suchen Sie zuerst mit so etwas wie der Chrome Developer Tool-Oberfläche das Objekt in der DOM-Baumhierarchie und untersuchen Sie es und finden Sie das Objekt, das die Binärdatei Ihres Bildes enthält.

Versuchen Sie, dieses Objekt auf null zu setzen, z var obj = null;.

Das sollte Javascript mitteilen, dass auf das untergeordnete Element nicht mehr verwiesen wird, und erzwingen, dass der Speicher des Objekts freigegeben wird.

  • Was genau meinst du mit “Javascript-Objekte selbst werden nicht von der Garbage Collection erfasst“? Benötigt mehr Erklärung oder ist – im Allgemeinen – falsch.

    – Bergi

    14. Dezember 2012 um 8:43 Uhr


  • Entschuldigung, ja, sie werden von der Garbage Collection erfasst, aber nicht immer sofort – haben Sie versucht, sie auf „null“ zu setzen, wie ich vorgeschlagen habe? Hat es geholfen? Hat es auch geholfen, das Chrom zu verwenden, um das Objekt im DOM-Baum zu finden?

    – Michael Galaxie

    26. Dezember 2012 um 18:12 Uhr

Einstellung auf null war zumindest hier die Lösung. (Firefox 69)

In einem Projekt lade ich viele Bilder in Stapeln von 1 – 5 zum Vergleich. Bilder mit durchschnittlich 8-9 MB. Ohne Einstellung img Elemente zu null Nach dem Entfernen war der RAM-Aufbau erheblich und erschöpfte den verfügbaren Speicher.

Also abgeändert hiervon:

function clear (n) {
    while (n.lastChild) {
        n.removeChild(n.lastChild);
    return n;
};

dazu:

function clear (n) {
    let x;
    while (n.lastChild) {
        x = n.removeChild(n.lastChild);
        x = null;
    }
    return n;
};

Jetzt gibt es überhaupt keinen RAM-Aufbau.

Benutzer-Avatar
hque1011

Was ist mit dem Festlegen der Bilder als Hintergründe für Divs? Ich glaube, Flickr macht so etwas für seine mobile HTML5-App.

1187710cookie-checkWie kann ich Speicherlecks beim Entfernen von Bildern im DOM verhindern?

This website is using cookies to improve the user-friendliness. You agree by using the website further.

Privacy policy