javascript,循环引用和内存泄漏

时间:2010-01-04 14:29:15

标签: javascript memory-leaks browser circular-reference

从我记得的一个不太遥远的过去,Javascript解释器在面对循环引用时遇到了内存泄漏问题。

最新的浏览器仍然如此吗? (例如Chrome,FF 3.5等)

3 个答案:

答案 0 :(得分:28)

当您在JavaScript对象和DOM节点等主机对象之间建立引用循环时,我们与JavaScript讨论的绝大多数泄漏都特别在IE6-7中。

在IE6中,这是特别有害的,因为当你离开页面时你没有得到回忆;它一直消失,直到你退出浏览器。在IE7中清除页面现在会返回内存,但是当你有一个长时间运行的应用程序时仍然会遇到困难。 IE8通过将DOM节点转换为本机JavaScript对象而不是主机对象来正确解决大部分问题。 (您仍然可以通过在参考循环中包含其他非本机对象(如ActiveX对象)来触发IE8中的泄漏。)

对于所有浏览器,随机位置肯定会出现小的模糊内存泄漏,特别是在旧版本中。但是没有一种方法可以像IE refloop问题那样轻松地分类和避免它们。

答案 1 :(得分:17)

要添加 bobince 答案,我使用 IE8 进行了一些测试。

我尝试了http://www.javascriptkit.com/javatutors/closuresleak/index.shtml

提供的几乎所有示例

除了移除仍然附加有事件的子节点的示例之外,其中没有人会再次泄露内存(至少不是以可察觉的方式)。

这种类型的例子我认为Douglas Crockford在他的queuetest2中有更好的解释。

这个仍然会泄漏IE8上的内存,只需运行the test script并查看Windows任务管理器 - 性能 - PF使用情况,即可轻松测试。你会发现每次循环PF使用量增加了近1MB(非常快)。

但IE8中的内存在页面卸载上发布(例如导航到新页面重新加载同一页面),显然也是当完全关闭浏览器时。

因此,为了让最终用户能够感知到IE8上的内存泄漏(因为系统性能降低),他需要长时间保持在同一页面上,现在这种情况经常发生在AJAX上,但是这个页面还需要数百个子节点删除附加了事件的元素

道格拉斯·克罗克福德测试强调浏览器添加 10000个节点然后删除,这非常适合向您展示问题,但在现实生活中我从未有过删除10个以上元素的页面。 INMHO通常使用display: none而不是删除整个节点集更快,这就是为什么我不使用removeChild那么多。


对于上面解释的对IE8内存泄漏更感兴趣的人,我做了另一个测试,当使用innerHTML 时,似乎内存泄漏在IE8中根本没有出现appendChild/removeChild添加/删除附加事件的子元素。所以显然道格拉斯·克罗克福德purge function(由他建议防止IE中的内存泄漏)在IE8中不再需要了,至少在使用innerHTML时...

感谢以下4esn0k评论) ...而且道格拉斯·克罗克福德purge function在IE8上根本不起作用,在他的代码var a = d.attributes中返回NO onclick属性(或任何其他onevent属性) IE8上的运行时(它们在IE7上返回)。

道格拉斯克罗克福德说:

  

“在删除任何元素之前,应该调用清除函数   通过removeChild方法,或者通过   设置 innerHTML 属性。“

我在这里提供测试代码:

<body>    
   <p>queuetest2 similar to the one provided by Douglas Crockford
   at http://www.crockford.com/javascript/memory/leak.html
   <br>but this one adds/removes spans using innerHTML
   instead of appendChild/removeChild.</p>

   <div id="test"></div>    
   <script>
       /* ORIGINAL queuetest2 CODE FROM DOUGLAS CROCKFORD IS HERE
          http://www.crockford.com/javascript/memory/queuetest2.html */

      (function (limit, delay) 
      {
          var n = 0;
          var add = true;

          function makeSpan(n) 
          {
              var div = document.getElementById('test');
              //adding also an inline event to stress more the browser
              div.innerHTML = "<span onmouseover=\"this.style.color = '#00ff00';\">" + n + "</span>";
              var s = div.getElementsByTagName('span')[0];
              s.onclick = function(e) 
              {
                  s.style.backgroundColor = 'red';
                  alert(n);
              };
              return s;
          }

          function process(n) 
          {
              if(add)                    
                 s = makeSpan(n);
              else
                 s.parentNode.innerHTML = ""; //removing span by clearing the div innerHTML
              add = !add;
          }

          function loop() 
          {
              if (n < limit) 
              {
                  process(n);
                  n += 1;
                  setTimeout(loop, delay);
              }
          }

          loop();
      })(10000, 10);

   </script>
</body>

答案 2 :(得分:2)

关于Internet Explorer 8 - 他们说他们已经在MS IE8中修复了它:http://msdn.microsoft.com/en-us/library/dd361842(VS.85).aspx

StackOverflow上的类似帖子:Do you know what may cause memory leaks in JavaScript?