IE6中的javascript内存泄漏与基本的jquery ui插件

时间:2011-02-15 01:00:23

标签: javascript jquery jquery-ui memory-leaks internet-explorer-6

首先,我在这个问题上进行了广泛的阅读和研究。我正在关注jquery UI的票证。我知道解决这个问题的方法,但我很好奇为什么会这样。我相信这个错误是由于关闭,但我的javascript-fu不是专家。

我认为jquery UI团队有更好的事情要做,而不是花费精力来处理IE6错误。所以我想把它带到一般的javascript public。

以下是测试用例:

<!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>

我已经使用jquery 1.4.4和1.5以及jquery-ui-1.8.9和jquery-ui master(写作时)的所有组合进行了测试,但它们都产生了相同的结果。

我认为我的测试小部件是最简单的。

如果使用sIEve进行测试,则可以发现泄漏。否则,将计数器增加到1000,你会很容易看到内存增加。您可以使用另一个来自Microsoft的tool来检测泄漏。

因此泄漏是由于小部件的_createWidget方法中的自定义事件绑定所致:

var self = this;
this.element.bind( "remove." + this.widgetName, function() {
    self.destroy();
});

所以,如果我发表评论,那就没有泄密。我使用1.8.9而不是master,因为1.8.9的widget代码看起来更简单(master已经改变了一点)。

现在,如果我完全将小部件之外的相同事件绑定在一起,那么也没有泄漏。例如,我在创建小部件之后但在destroy之前插入以下代码:

$("#inner").bind("remove.test", function() {});

我故意添加了一个无操作函数,但回调函数中的内容并不重要。你可以争辩说,因为我之后手动破坏,所以不需要绑定。但这不是重点。

所以我的问题是为什么原始代码,小部件代码中的绑定调用会泄漏?我怀疑这是因为关闭,但我无法解释。

有人可以解释一下吗?

2 个答案:

答案 0 :(得分:2)

据我所知,当JS变量指向DOM对象时,JS和DOM之间存在循环引用,并且该DOM对象具有指向返回的属性(或通常是事件处理程序)时,问题就会发生JS变量。上面的.bind()示例似乎是这样做的。显然,IE在其垃圾收集过程中使用引用计数,并且不会收集循环引用。

我见过至少有几个MSDN博客将此归咎于JavaScript并且基本上建议避免关闭,这显然不是很有帮助,但这里有一些非Microsoft / MSDN文章讨论问题并提供一些解决方法:

http://laurens.vd.oever.nl/weblog/items2005/closures/

http://www.ibm.com/developerworks/web/library/wa-memleak/

JavaScript Closures and Memory Leaks

答案 1 :(得分:0)

对不起,我无法解释此问题的原因,但我采取了一种解决方法,以防止发生这种相当恼人的泄漏。

在我的页面中包含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任务管理器在浏览包含可排序小部件的页面时显示常量内存消耗。

经过数小时的搜索和测试后,我仍然无法找出泄漏的真正原因。