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

Javascript 删除DOM中的图像时如何防止内存泄漏?,javascript,html,webkit,Javascript,Html,Webkit,有一种情况是,当您从DOM中删除图像时,它不会释放与其关联的内存 这是经常加载图像的单页应用程序的一个问题 各种建议的解决方案包括: 在从DOM中删除图像之前,请将图像src设置为“” 在从DOM中删除图像之前,将图像设置为单像素图像 前三种方法不适合我。回收图像元素的主要缺点是,这意味着要编写大量代码来管理图像元素。我正在通过AJAX加载可能包含图像的新HTML,因此我不一定知道将加载的图像数量 是否有其他解决方法来解决此问题?尝试将Javascript DOM树对象设置为“null”

有一种情况是,当您从DOM中删除图像时,它不会释放与其关联的内存

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

各种建议的解决方案包括:

  • 在从DOM中删除图像之前,请将图像src设置为“”
  • 在从DOM中删除图像之前,将图像设置为单像素图像
前三种方法不适合我。回收图像元素的主要缺点是,这意味着要编写大量代码来管理图像元素。我正在通过AJAX加载可能包含图像的新HTML,因此我不一定知道将加载的图像数量


是否有其他解决方法来解决此问题?

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

首先,使用类似于chrome开发者工具界面的东西,在DOM树层次结构中找到对象,并检查它,找到包含图像二进制的对象

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


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

将图像作为背景设置为div怎么样?我相信Flickr正在为他们的移动html5应用程序做类似的事情。

一个基本的图像池应该允许你回收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 ) );
    }
在页面的某个位置放置一个隐藏的“图像池”容器,以便在使用之间隐藏回收的图像:

<div id="image_pool" style="display:none;"></div>
当你完成它时:

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

(回收工作同上)

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

首先。添加了一组图像,并将垃圾收集留在浏览器中。

它肯定是垃圾收集的,但是过了一段时间,确保不需要创建图像

。为图像的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);
}
var s=“data:image/png;base64,ivborw0kggoaaaansuhueugaaaaaaaafcayaacnblaaaaheleqvqi12p4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=”;
对于(变量i=0;i<100;i++){
var img=document.createElement(“img”);
img.src=s;
document.getElementById(“myList1”).appendChild(img);
setTimeout(函数(){img=null;},1000);
}

这看起来很相似,但对我来说更好一点,因为我在浏览器前观看,发现使用的内存更少,垃圾收集几乎与上面相同

第三。在代码中执行垃圾收集

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);
}
var s=“data:image/png;base64,ivborw0kggoaaaansuhueugaaaaaaaafcayaacnblaaaaheleqvqi12p4//8/w38GIAXDIBKE0DHxgljNBAAO9TXL0Y4OHwAAAABJRU5ErkJggg=”;
对于(变量i=0;i<100;i++){
var img=document.createElement(“img”);
img.src=“dot.png”;//或其他,两者在此处的含义相同。
img.src=s;
document.getElementById(“myList1”).appendChild(img);
setTimeout(函数(){img=null;},1000);
}

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


总而言之,当您觉得必须释放某些内容时,最好自己使用垃圾收集。设置为
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;
};

现在根本没有内存积累。

我认为映像池不会有那么多代码;而且它可以很容易地支持任意数量或图像。删除
src
属性有什么问题?取决于什么(和如果)您正在使用的库在删除img之前,您可以先通过删除
src
包装节点删除函数来处理这种特殊情况。刚刚更新了我的问题-删除src属性对我不起作用。如果手动调用每个图像的Image()构造函数,您怎么可能不知道图像的数量(链接错误的原因)。我不认为这个错误涵盖了使用img标记注入html的问题。你说的“Javscript对象本身不被垃圾收集”到底是什么意思?需要更多的解释,或者-一般来说-是错误的。对不起,是的,它们是垃圾收集的,但并不总是立即收集的-您是否尝试按照我的建议设置为“null”?是否有用?使用chrome在DOM树中定位对象是否也有帮助?我不确定,但在JQuery中分离实际上会破坏节点,appendTo会创建一个新的否DOM中的de。因此实际上根本没有回收。有趣的是,我必须查看源代码以进行验证。无论哪种方式,我都会在这里添加一个不使用jQuery函数的版本,仅供参考。在这里发布了一个问题:@GuillermoGutiérrez听起来像是在detach()和remove()中都保留了元素函数,所以在我上面的代码中,元素应该按照预期正确循环使用。使用
数据:URI
你错过了所有浏览器HTTP缓存…在生产应用程序中,这将非常明显。有效点。我通常将所有元素都放在
css
js
中并缓存这些资产。是的,但在这个应用程序中,图像是内容,所以它不会起作用。怎么会不起作用?我不想反对你,但这种方法怎么会不起作用呢
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;
};