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

问题描述 投票:38回答:5

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

这是经常加载图像的单页应用程序的问题。

各种建议的解决方案是:

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

还有其他解决方法来解决此问题吗?

javascript html webkit
5个回答
12
投票

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

First。确实添加了一组图像并将垃圾回收留给了浏览器。“在此处输入图像描述”

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

第二。对图像的src使用了data: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);
}

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9TTW1ldS5wbmcifQ==” alt =“在此处输入图像描述”>

这看起来很相似,虽然对我来说更好,因为我在浏览器前观看时发现使用的内存更少,并且垃圾回收与上面几乎相同。

第三。是否在代码中进行了垃圾回收。

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

<< img src =“ https://image.soinside.com/eyJ1cmwiOiAiaHR0cHM6Ly9pLnN0YWNrLmltZ3VyLmNvbS9kNzNqUS5wbmcifQ==” alt =“在此处输入图像描述”>

在这么短的测试时间内,我相信最后一种方法效果更好,因为它几乎立即释放了空间,而无需等待是否进一步需要参考图像。

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


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

(回收工作与上述相同)


0
投票

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

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

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

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


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堆积。


-1
投票

将图像设置为div的背景呢?我相信Flickr正在为他们的移动html5应用执行类似操作。

© www.soinside.com 2019 - 2024. All rights reserved.