【问题标题】:Javascript event handlers always increase browser memory usageJavascript 事件处理程序总是会增加浏览器内存使用量
【发布时间】:2009-01-29 13:06:53
【问题描述】:

编辑:在进一步检查中,Firefox 似乎没有这样做,但 Chrome 肯定会这样做。我猜这只是新浏览器的一个错误 - 对于每个事件,Chrome 中都会发生 I/O 读取,但 FF 中不会发生。

当我在浏览器中加载以下页面时(我在 Vista 下的 Chrome 和 Firefox 3 中进行了测试)并在周围移动鼠标时,内存总是增加,而且似乎永远不会减少。

这是:

  1. 浏览器的预期行为
  2. 浏览器内存泄漏或
  3. 显示的代码中存在内存泄漏?

.

<!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01//EN" "http://www.w3.org/TR/html4/strict.dtd">
<html>
<head>
    <meta http-equiv="Content-Type" content="text/html; charset=iso-8859-1" />
    <title>test</title>
</head>
<body>
   <script>
      var createEl = function (i) {
          var el = document.createElement("div");
          var t = document.createTextNode(i.toString());
          el.appendChild(t);
          t=null;
          el.id=i.toString();

          var fn = function (e) {};
          el.addEventListener("mouseover", fn, false);
          //el.onmouseover = fn;
          fn = null;

          try{
            return el;
          }
          finally{
            el=null;
          }
          //return (el = [el]).pop();
        };

        var i,x;
        for (i= 0; i < 100; i++){
          x = createEl(i)
          document.body.appendChild(x);
          x = null;
        }
   </script>
</body>
</html>

(el = [el].pop())try/finally 的想法都来自 here,尽管它们似乎都没有帮助 - 可以理解,因为它们只是用于 ie6 修复。

我还尝试过使用 addEventListener 和 onmouseover 方法来添加事件。我发现防止内存增加的唯一方法是注释掉这两行代码。

【问题讨论】:

  • 您在真实脚本中的 mouseover 事件处理程序中有任何内容吗?我无法重现您的问题。 (FF 3.0.5 Linux)
  • 上面的代码是我正在测试并遇到问题的逐字记录。它不会立即发生,大约需要 20 秒左右移动鼠标才能开始显示。在我看来,好像某些缓冲区最终会不堪重负。
  • 在进一步的测试中,FF似乎在上述代码上没有这个问题,只有Chrome。

标签: javascript memory-leaks event-handling


【解决方案1】:

fn 是一个闭包,即使其中没​​有代码。例如。尝试使用 Firebug 进行调试并在该函数内设置断点。闭包中定义的所有变量(fn 代码 + 挂起的变量 = 闭包)理论上都是可访问的(虽然我不知道如何在实践中访问它们)。

【讨论】:

    【解决方案2】:

    与事件处理程序相关的内存泄漏通常与外壳有关。换句话说,将函数附加到指向其元素的事件处理程序可以防止浏览器进行垃圾收集。 (谢天谢地,大多数较新的浏览器已经“学会了诀窍”并且在这种情况下不再泄漏内存,但是有很多旧浏览器漂浮在那里!)

    这样的外壳可能如下所示:

    var el = document.createElement("div");
    var fnOver = function(e) {
        el.innerHTML = "Mouse over!";
    };
    var fnOut = function(e) {
        el.innerHTML = "Mouse out.";
    };
    
    el.addEventListener("mouseover", fnOver, false);
    el.addEventListener("mouseout", fnOut, false);
    
    document.getElementsByTagName("body")[0].appendChild(el);
    

    fnOverfnOut 到达它们的封闭范围以引用 el 的事实是创建了一个封闭(实际上是两个 - 每个函数一个)并可能导致浏览器泄漏。您的代码不会做这样的事情,因此不会创建任何外壳,因此不应导致(行为良好的)浏览器泄漏。

    我猜,这只是测试版软件中最糟糕的一款。 :-)

    【讨论】:

      【解决方案3】:

      嗯,这不是我处理这个问题的方式,我无法复制这种行为,所以我只能告诉你,你在记忆方面遇到的问题很可能是因为fn 函数中的任何内容,除非它是一个闭包,否则您应该在 createEl 函数之外定义 fn 并仅在其中引用它,因此内存中只存在一个实例。

      您需要更好地处理事件绑定(这不是 xbrowser 安全的 - 在这一点上我犹豫是否建议使用 jQuery),并且整个 (el =[el]).pop() 对我来说是巫毒的恶臭,尽管我很高兴得到纠正如果有人可以准确地解释它所取得的成就。

      【讨论】:

      • 这只是一个测试,以确定浏览器是否泄漏,而不是 xbrowser 安全。我不认为 IE 值得测试内存泄漏。 fn 不是闭包。它里面没有代码。
      • “voodoo”确保不维护对 el 的引用。 el = [el] 使以前在 el 中的值现在在 el 中的数组中。随后的 pop 删除了数组的内容,并在此过程中删除了对其的任何引用。这确保了创建的 DOM el 中没有悬挂的 refs。
      • 所以,如果您还有问题,请打破 fn 并在其中发布代码
      • 我更改了它,以便在 createEl 上面的行中声明 fn,但它具有相同的效果。我不明白为什么函数是为每个 dom 元素创建还是只创建一次,只要它不是为每个事件创建的。我的猜测是事件对象本身会泄漏内存。
      • @wbecker - 有任何证据吗? google 到目前为止没有产生任何结果,我不明白为什么 GC 会比 var 退出函数范围更感兴趣
      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多