jQuery的内存泄漏与DOM去除(jQuery memory leak with DOM remo

2019-07-19 01:48发布

下面是使用jQuery IE8泄漏内存死简单的网页(我通过看我的iexplore.exe进程比增长在Windows任务管理器时的内存使用情况检测内存泄漏):

<html>
<head>
    <title>Test Page</title>
    <script type="text/javascript" src="jquery.js"></script>
</head>
<body>
<script type="text/javascript">
    function resetContent() {
        $("#content div").remove();
        for(var i=0; i<10000; i++) {
            $("#content").append("<div>Hello World!</div>");
        }
        setTimeout(resetTable, 2000);
    }
    $(resetContent);
</script>
<div id="content"></div>
</body>
</html>

显然,即使在调用时jQuery.remove()函数我仍然遇到一些内存泄漏。 我可以写经历没有内存泄漏如下我自己删除功能:

$.fn.removeWithoutLeaking = function() {
    this.each(function(i,e){
        if( e.parentNode )
            e.parentNode.removeChild(e);
    });
};

这一切正常,并没有泄漏任何记忆。 那么,为什么jQuery的内存泄漏? 我创建了一个基于另一个remove函数jQuery.remove()这确实导致泄漏:

$.fn.removeWithLeakage = function() {
    this.each(function(i,e) {
        $("*", e).add([e]).each(function(){
            $.event.remove(this);
            $.removeData(this);
        });
        if (e.parentNode)
            e.parentNode.removeChild(e);
    });
};

有趣的是,内存泄漏似乎是由每个调用哪个jQuery包含以防止内存泄漏从与被删除的DOM元素相关联的事件和数据造成的。 当我打电话removeWithoutLeaking功能,那么我的记忆中停留一段时间不变,但是当我打电话removeWithLeakage不是那么它只是不断增长。

我的问题是,怎么样,每个呼叫

$("*", e).add([e]).each(function(){
    $.event.remove(this);
    $.removeData(this);
});

可能被导致内存泄漏?

编辑:在码修正错字,其在重新测试,证明对结果没有任何影响。

进一步编辑:我已经提交给jQuery的项目的bug报告,因为这似乎是一个jQuery错误: http://dev.jquery.com/ticket/5285

Answer 1:

我想大卫可能会在一些与涉嫌removeChild之泄漏,但我不能在IE8重现它...它可以在早期的浏览器以及发生的,但是这不是我们这里。 如果我手动removeChild之的div没有泄露; 如果我改变jQuery来使用outerHTML= '' (或移动到仓随后bin.innerHTML)代替removeChild之仍然存在泄漏。

在淘汰的过程,我开始在位黑客remove jQuery中。 1.3.2线1244:

//jQuery.event.remove(this);
jQuery.removeData(this);

注释掉该行没有导致泄漏。

那么,让我们来看看event.remove,它调用data('events')以查看是否有连接到元素的任何事件。 什么是data在做什么?

// Compute a unique ID for the element
if ( !id )
    id = elem[ expando ] = ++uuid;

哦。 所以,它的加入jQuery的UUID到数据查找条目劈特性之一每个元素甚至尝试读取数据上,其中包括你移除元素的每一个后代! 多么愚蠢。 我可以短路,通过加入这行之前它:

// Don't create ID/lookup if we're only reading non-present data
if (!id && data===undefined)
    return undefined;

这似乎修复泄漏对于这种情况在IE8。 不能保证它不会打破东西是jQuery的迷宫一样,但在逻辑上是有意义的。

至于我可以工作,泄漏简直是jQuery.cache对象(也就是数据存储,而不是一个真正的高速缓存这样)越来越大,作为一个新的关键是为每个删除的元素加入。 虽然removeData应删除这些缓存条目OK,IE不会出现,当你恢复空间delete从对象的关键。

(无论哪种方式,这是哪门子的jQuery的行为,我不欣赏的一个例子,它是橱什么应该是一个平凡简单的操作......其中一些下做太多是很值得怀疑的东西,整个用的expando和东西什么jQuery不会给innerHTML通过正则表达式来防止显示在IE属性是刚刚打破和丑陋,而且使消气的习惯和setter相同功能的混乱,在这里,在错误的结果。 )

[古怪,留下leaktest为长时间结束了偶尔给完全虚假的错误在jquery.js和之前的记忆居然跑了出来......还有像“意想不到的命令”,我注意到一个“节点名称为空或不对象”在行667,这是据我可以看到甚至不应该已经在运行,更谈不上有对节点名称是空的检查有! IE浏览器是不是给我很大的信心在这里...]



Answer 2:

似乎是固定jQuery中1.5(23二月版本)。 我跑进与1.4.2同样的问题,并与DOM去除如上第一固定,然后通过尝试新的版本。



Answer 3:

元素移除一个内在的DOM问题。 这是要和我们呆在一起。 同上。

jQuery.fn.flush = function()
/// <summary>
/// $().flush() re-makes the current element stack inside $() 
/// thus flushing-out the non-referenced elements
/// left inside after numerous remove's, append's etc ...
/// </summary>
{ return jQuery(this.context).find(this.selector); }

相反黑客JQ的,我用这个扩展。 特别是在大量删除()和克隆()的网页:

$exact = $("whatever").append("complex html").remove().flush().clone();

同时,也是下一个确实的帮助:

// remove all event bindings , 
// and the jQ data made for jQ event handling
jQuery.unbindall = function () { jQuery('*').unbind(); }
//
$(document).unload(function() { 
  jQuery.unbindall();
});


Answer 4:

看到了jQuery 1.4路线图http://docs.jquery.com/JQuery_1.4_Roadmap 。 具体而言,节“卸下摆臂后使用.outerHTML清理()”与IE发生由于remove函数内存泄漏问题的交易被调用。

也许你的问题会在下一版本中得到解决。



Answer 5:

它是否仍然泄漏如果调用empty ,而不是remove

$("#content").empty();


Answer 6:

JQuery的1.4.1有以下几点:

    cleanData: function (elems) {
        for (var i = 0, elem, id; (elem = elems[i]) != null; i++) {
            jQuery.event.remove(elem);
            jQuery.removeData(elem);
        }
    }

这里是我不得不修改,以消除漏水的问题是什么:

    cleanData: function (elems) {
        for (var i = 0, elem, id; (elem = elems[i]) != null; i++) {
            jQuery.event.remove(elem);
            jQuery.removeData(elem);
            jQuery.purge(elem);
        }
    }

附加功能:

    purge: function (d) {
        var a = d.childNodes;
        if (a) {
            var remove = false;
            while (!remove) {
                var l = a.length;
                for (i = 0; i < l; i += 1) {
                    var child = a[i];
                    if (child.childNodes.length == 0) {
                        jQuery.event.remove(child);
                        d.removeChild(child);
                        remove = true;
                        break;
                    }
                    else {
                        jQuery.purge(child);
                    }
                }
                if (remove) {
                    remove = false;
                } else {
                    break;
                }
            }
        }
    },


文章来源: jQuery memory leak with DOM removal