带有基本jquery ui插件的IE6中的javascript内存泄漏
首先,我对这个问题进行了广泛的阅读和研究。已经有一张票了,我正在跟踪。我知道解决这个问题的方法,但我很好奇为什么会发生这种情况。我相信这个错误是由于一个关闭,但我的javascript fu不是专家 我认为jQueryUI团队要做的事情比花精力在IE6 bug上要好。所以我想把这件事告诉大众 以下是一个测试用例:带有基本jquery ui插件的IE6中的javascript内存泄漏,javascript,jquery,jquery-ui,memory-leaks,internet-explorer-6,Javascript,Jquery,Jquery Ui,Memory Leaks,Internet Explorer 6,首先,我对这个问题进行了广泛的阅读和研究。已经有一张票了,我正在跟踪。我知道解决这个问题的方法,但我很好奇为什么会发生这种情况。我相信这个错误是由于一个关闭,但我的javascript fu不是专家 我认为jQueryUI团队要做的事情比花精力在IE6 bug上要好。所以我想把这件事告诉大众 以下是一个测试用例: <!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml">
<head>
<title>jquery ui memory leak test</title>
<script type="text/javascript" src="jquery-1.5.js"></script>
<script type="text/javascript" src="jquery.ui.widget.js"></script>
<script type="text/javascript">
(function($) {
$.widget("ui.test", {
_create: function() {
}
});
$(document).ready(function() {
for (var i = 0; i < 1; i++) {
$("#container").append("<div id='inner'></div>");
$("#inner").test();
$("#inner").test("destroy");
$("#container").empty();
};
});
})(jQuery);
</script>
</head>
<body>
<div id="container">
</div>
</body>
</html>
所以,如果我把这些评论出来,就不会有任何泄漏。我使用的是1.8.9而不是master,因为1.8.9的小部件代码似乎更简单(master有点变化)
现在,如果我将同一事件绑定到小部件之外,那么也不会有泄漏。例如,我会在创建小部件之后但在销毁之前插入以下代码:
$("#inner").bind("remove.test", function() {});
我特意添加了一个no-op函数,但回调函数中的内容并不重要。你可能会说,因为我在事后手动销毁,所以绑定是不必要的。但这不是重点
所以我的问题是,为什么原始代码,小部件代码中的绑定调用会泄漏?我怀疑这是由于结案,但我无法解释
有人能解释一下吗?据我所知,当JS和DOM之间存在循环引用,当JS变量指向DOM对象,并且该DOM对象有一个指向JS变量的属性(或者通常是事件处理程序)时,就会出现问题。上面使用.bind()的示例似乎可以做到这一点。显然IE在垃圾收集过程中使用了引用计数,循环引用不会被收集 我已经看到至少有几个MSDN博客将此归咎于JavaScript,并基本上建议避免闭包,这显然不是很有帮助,但以下是一些非Microsoft/MSDN文章,讨论了这个问题并给出了一些解决方法:
很抱歉,我无法解释此问题的原因,但我已制定了一个解决方案,以防止发生这种相当恼人的泄漏 在我的页面中包括jquery和jquery ui后,我添加了以下代码:
var origCreateWidget = $.Widget.prototype._createWidget;
$.Widget.prototype._createWidget = function( options, element ) {
var origBind = $.fn.bind;
var widget = this;
$.fn.bind = function( type, func ) {
if( typeof( type ) === "string" && type.indexOf( "remove." ) === 0) {
// ignore the remove events
}
else {
origBind.apply( this, arguments );
}
return this;
}
var res = origCreateWidget.call( this, options, element );
$.fn.bind = origBind;
return res;
};
另外,当窗口卸载事件发生时,我调用destroy
。在这些更改之后,sIEve不会报告任何泄漏,windows任务管理器在浏览包含可排序小部件的页面时会显示持续的内存消耗
经过数小时的搜索和测试,我仍然无法找出泄漏的真正原因
var origCreateWidget = $.Widget.prototype._createWidget;
$.Widget.prototype._createWidget = function( options, element ) {
var origBind = $.fn.bind;
var widget = this;
$.fn.bind = function( type, func ) {
if( typeof( type ) === "string" && type.indexOf( "remove." ) === 0) {
// ignore the remove events
}
else {
origBind.apply( this, arguments );
}
return this;
}
var res = origCreateWidget.call( this, options, element );
$.fn.bind = origBind;
return res;
};