在DOM中删除图像时如何防止内存泄漏?

时间:2012-12-13 11:39:56

标签: javascript html webkit

有一个known bug in webkit,当您从DOM中删除图像时,它不会释放与之关联的内存。

这是单页应用经常加载图片的问题。

各种建议的解决方案是:

前三种方法对我不起作用。回收图像元素的主要缺点是它意味着编写大量代码来管理它。我正在通过AJAX加载可能包含图像的新HTML,因此我不一定知道要加载的图像数量。

还有其他解决方法可以解决这个问题吗?

5 个答案:

答案 0 :(得分:12)

我使用了3种不同类型的方法......

<强>第一即可。添加了一组图像并将垃圾收集留给了浏览器。 enter image description here

它肯定是垃圾收集,但过了一会儿,确保不需要已经创建的图像。

<强>第二即可。使用了数据:图像的src的URI模式。

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

enter image description here

这看起来很相似,虽然对我来说有点好,因为我在浏览器前观看并观察到使用较少的内存,垃圾收集几乎与上面相同。

<强>第三即可。在代码中进行了垃圾收集。

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

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

enter image description here

在这短暂的测试时间里,我相信最后一种方法效果更好,因为它几乎可以立即释放空间,而无需等待进一步查看引用图像是否需要。

总而言之,当您绝对觉得必须释放某些东西时,最好自己使用垃圾收集。

答案 1 :(得分:1)

基本图像池应该允许您回收img元素以便重复使用。由于您不知道有多少图像会提前完成,因此只需根据需要扩展池大小。

这样的事情应该有效:

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

在您的页面上放置一个隐藏的“image_pool”容器,以便在使用之间隐藏回收的图像:

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

然后,只要您需要新的img元素,请致电:

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

当你完成它时:

recycleImg( 'my_image_id' );

jQuery替代

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

当您需要新的img元素时:

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

(回收与上述相同)

答案 2 :(得分:0)

尝试将Javascript DOM树对象设置为“null”。

首先,使用chrome开发人员工具界面之类的东西,在DOM树层次结构中找到对象并检查它,然后找到包含图像二进制文件的对象。

尝试将该对象设置为null,例如var obj = null;

这应该告诉Javascript不再引用子项并强制释放对象的内存。

答案 3 :(得分:0)

设置为null至少是这里的解决方案。 (Firefox 69)

在一个项目中,我以1-5的批量加载图像以进行比较。图片平均8-9MB。删除后未将img元素设置为null时,RAM的累积非常重要,甚至耗尽了可用内存。

因此,更改为:

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

对此:

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

现在完全没有RAM。

答案 4 :(得分:-1)

如何将图像设置为div的背景?我相信Flickr正在为他们的移动html5应用程序做这样的事情。