jQuery内存泄漏与DOM删除 [英] jQuery memory leak with DOM removal

查看:110
本文介绍了jQuery内存泄漏与DOM删除的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

这是一个非常简单的网页,使用jQuery泄漏了IE8中的内存(我通过观察Windows任务管理器中iexplore.exe进程的内存使用量随着时间的增长来检测内存泄漏):

Here's a dead-simple webpage that leaks memory in IE8 using jQuery (I detect memory leaks by watching the memory usage of my iexplore.exe process grow over time in the Windows Task Manager):

<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()函数,我仍然会遇到一些内存泄漏.我可以编写自己的删除函数,该函数不会遇到内存泄漏,如下所示:

Apparently even when calling the jQuery.remove() function I still experience some memory leakage. I can write my own remove function that experiences no memory leak as follows:

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

这工作得很好,并且不会泄漏任何内存.那么,为什么jQuery会泄漏内存呢?我基于jQuery.remove()创建了另一个删除函数,这确实会导致泄漏:

This works just fine and doesn't leak any memory. So why does jQuery leak memory? I created another remove function based on jQuery.remove() and this does indeed cause a leak:

$.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时,它就一直在增长.

Interestingly, the memory leak seems to be caused by the each call which jQuery includes to prevent memory leaks from events and data associated with the DOM elements being deleted. When I call the removeWithoutLeaking function then my memory stays constant over time, but when I call removeWithLeakage instead then it just keeps growing.

我的问题是,每次通话该怎么办

My question is, what about that each call

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

是否可能导致内存泄漏?

could possibly be causing the memory leak?

修复了代码中的错字,该错字在重新测试后被证明对结果没有影响.

Fixed typo in code which, upon retesting, proved to have no effect on the results.

进一步我已经向jQuery项目提交了错误报告,因为这似乎是jQuery错误:

FURTHER I have filed a bug report with the jQuery project, since this does seem to be a jQuery bug: http://dev.jquery.com/ticket/5285

推荐答案

我以为David可能涉嫌涉嫌removeChild泄漏,但我无法在IE8中重现它……这很可能发生在较早的浏览器中,但这不是我们这里拥有的.如果我手动删除div的子代,则没有泄漏;如果我将jQuery更改为使用outerHTML= ''(或移动到bin后跟bin.innerHTML)而不是removeChild,仍然存在泄漏.

I thought David might be onto something with the alleged removeChild leak, but I can't reproduce it in IE8... it may well happen in earlier browsers, but that's not what we have here. If I manually removeChild the divs there is no leak; if I alter jQuery to use outerHTML= '' (or move-to-bin followed by bin.innerHTML) instead of removeChild there is still a leak.

在消除过程中,我开始对jQuery中remove的位进行黑客攻击. 1.3.2中的第1244行:

In a process of elimination I started hacking at bits of remove in jQuery. line 1244 in 1.3.2:

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

注释该行不会导致泄漏.

Commenting out that line resulted in no leak.

因此,让我们看一下event.remove,它调用data('events')来查看是否有任何事件附加到元素上. data在做什么?

So, let's look at event.remove, it calls data('events') to see if there are any events attached to the element. What is data doing?

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

哦.因此,它为jQuery甚至试图读取的每个元素添加了jQuery的uuid-to-data-lookup条目hack属性之一,其中包括要删除的元素的每个后代!真傻我可以通过在此行之前将其短路:

Oh. So it's adding one of jQuery's uuid-to-data-lookup entry hack properties for every element it even tries to read data on, which includes every single descendent of an element you're removing! How silly. I can short-circuit that by putting this line just before it:

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

似乎可以解决IE8中这种情况下的泄漏.无法保证它不会破坏jQuery迷宫中的其他内容,但从逻辑上讲是有道理的.

which appears to fix the leak for this case in IE8. Can't guarantee it won't break something else in the maze that is jQuery, but logically it makes sense.

据我所知,泄漏只是jQuery.cache对象(它是数据存储,不是真正的缓存),随着为每个删除的元素添加新键,该泄漏越来越大.尽管removeData应该可以删除那些缓存条目,但是当您从对象delete键时,IE似乎无法恢复该空间.

As far as I can work out, the leak is simply the jQuery.cache Object (which is the data store, not a really a cache as such) getting bigger and bigger as a new key is added for every removed element. Although removeData should be removing those cache entries OK, IE does not appear to recover the space when you delete a key from an Object.

(无论哪种方式,这都是我不喜欢的jQuery行为的示例.对于应该是一个简单的操作,它在幕后做得太多了……其中有些是值得怀疑的东西.expando和> jQuery对通过正则表达式来防止在IE中显示为属性变得丑陋和丑陋.使getter和setter具有相同功能的习惯令人困惑,并且在这里导致bug.)

(Either way, this is an example of the sort of jQuery behaviour I don't appreciate. It is doing far too much under the hood for what should be a trivially simple operation... some of which is pretty questionable stuff. The whole thing with the expando and what jQuery does to innerHTML via regex to prevent that showing as an attribute in IE is just broken and ugly. And the habit of making the getter and setter the same function is confusing and, here, results in the bug.)

[奇怪的是,将泄漏测试延长了一段时间后,偶尔会在内存实际用完之前在jquery.js中产生完全虚假的错误……出现了类似意外命令"之类的情况,我注意到"nodeName是在第667行,"null or not a object"(据我所知甚至不应该运行),更不用说在那里检查一下nodeName是否为null! IE并没有给我太大的信心...]

[Weirdly, leaving the leaktest for extended periods of time ended up occasionally giving totally spurious errors in jquery.js before the memory actually ran out... there was something like ‘unexpected command’, and I noted a ‘nodeName is null or not an object’ at line 667, which as far as I can see shouldn't even have been run, let alone that there is a check there for nodeName being null! IE is not giving me much confidence here...]

这篇关于jQuery内存泄漏与DOM删除的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆