Eli*_*ght 46 jquery memory-leaks
这是一个死简单的网页,它使用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>
Run Code Online (Sandbox Code Playgroud)
显然即使在调用jQuery.remove()函数时我仍然会遇到一些内存泄漏.我可以编写自己的删除函数,不会发生内存泄漏,如下所示:
$.fn.removeWithoutLeaking = function() {
this.each(function(i,e){
if( e.parentNode )
e.parentNode.removeChild(e);
});
};
Run Code Online (Sandbox Code Playgroud)
这很好用,不泄漏任何内存.那为什么jQuery会泄漏内存呢?我创建了另一个基于的删除函数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);
});
};
Run Code Online (Sandbox Code Playgroud)
有趣的是,内存泄漏似乎是由jQuery包含的每个调用引起的,以防止事件和与删除的DOM元素相关的数据的内存泄漏.当我调用该removeWithoutLeaking函数时,我的记忆会随着时间的推移而保持不变,但是当我打电话时removeWithLeakage它会继续增长.
我的问题是,每个电话怎么样
$("*", e).add([e]).each(function(){
$.event.remove(this);
$.removeData(this);
});
Run Code Online (Sandbox Code Playgroud)
可能是导致内存泄漏?
编辑:修复了代码中的拼写错误,经过重新测试,证明对结果没有影响.
进一步编辑:我已经向jQuery项目提交了一个错误报告,因为这似乎是一个jQuery错误:http://dev.jquery.com/ticket/5285
bob*_*nce 58
我认为大卫可能会涉嫌removeChild泄漏,但我无法在IE8中重现它...它可能会在早期的浏览器中发生,但这不是我们在这里所拥有的.如果我手动removeChild divs没有泄漏; 如果我改变jQuery使用outerHTML= ''(或移动到bin然后bin.innerHTML)而不是removeChild仍然存在泄漏.
在消除过程中,我开始remove在jQuery中攻击一些内容.1.3.2中的第1244行:
//jQuery.event.remove(this);
jQuery.removeData(this);
Run Code Online (Sandbox Code Playgroud)
注释掉那条线导致没有泄漏.
所以,让我们看看event.remove,它调用data('events')以查看是否有任何事件附加到元素.在data做什么?
// Compute a unique ID for the element
if ( !id )
id = elem[ expando ] = ++uuid;
Run Code Online (Sandbox Code Playgroud)
哦.所以它为每个甚至尝试读取数据的元素添加了一个jQuery的uuid-to-data-lookup入口hack属性,其中包括你要删除的元素的每个后代!真傻.我可以通过在它之前放置这条线来短路:
// Don't create ID/lookup if we're only reading non-present data
if (!id && data===undefined)
return undefined;
Run Code Online (Sandbox Code Playgroud)
这似乎在IE8中解决了这种情况的泄漏.不能保证它不会破坏jQuery的迷宫中的其他东西,但逻辑上它是有道理的.
据我所知,泄漏只是jQuery.cache对象(它是数据存储,而不是真正的缓存)随着为每个被移除的元素添加新密钥而变得越来越大.尽管removeData应该删除那些缓存条目,但是当您delete从Object获取密钥时,IE似乎不会恢复该空间.
(无论哪种方式,这都是我不理解的jQuery行为的一个例子.它在做什么应该是一个简单的简单操作的内幕做得太多了......其中一些是相当可疑的东西.整个使用expando的东西以及jQuery innerHTML通过正则表达式做什么以防止在IE中显示为属性只是破坏和丑陋.而使得getter和setter具有相同功能的习惯令人困惑,并且在这里导致bug.)
[奇怪的是,在内存实际耗尽之前,在jquery.js中偶尔留下泄密测试结果偶尔会给出完全虚假的错误......有些事情就像'意外命令',我注意到'nodeName是否为null第667行的一个对象,据我所知,甚至不应该运行,更不用说有一个检查nodeName为null!IE在这里没有给我很多信心......]
| 归档时间: |
|
| 查看次数: |
39354 次 |
| 最近记录: |