24

从我回忆的不远的过去来看,Javascript 解释器在面对循环引用时会遇到内存泄漏问题。

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

4

3 回答 3

28

当您在 JavaScript 对象和宿主对象(如 DOM 节点)之间创建引用循环时,我们讨论的与 JavaScript 相关的绝大多数泄漏都具体发生在 IE6-7 中。

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

对于所有浏览器,尤其是在旧版本中,随机位置肯定仍然会潜伏着一些不明显的内存泄漏。但是没有一种方法可以像 IE 重新循环问题那样轻松分类和避免它们。

于 2010-01-04T16:11:13.547 回答
17

为了增加bobince答案,我用IE8做了一些测试。

我尝试了http://www.javascriptkit.com/javatutors/closuresleak/index.shtml提供的几乎所有示例

除了删除仍然附加事件的子节点的示例之外,它们中的任何一个都不再泄漏内存(至少不是以可感知的方式)。

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

仍然会在 IE8 上泄漏内存,只需运行测试脚本并查看 Windows 任务管理器 - 性能 - PF 使用情况,就可以很容易地进行测试。您会看到每个循环的 PF 使用率增加了近 1MB(非常快)。

在 IE8 中,内存在页面卸载时释放(例如导航到新页面重新加载同一页面),显然在完全关闭浏览器时也是如此。

因此,为了让最终用户在 IE8 上感知到这种内存泄漏(作为降低的系统性能),他需要长时间停留在同一页面上,这在现在 AJAX 经常发生,但是这个页面也需要执行数百个子节点删除带有事件的元素

Douglas Crockford 测试强调浏览器添加了 10000 个节点然后删除,这非常适合向您展示问题,但在现实生活中,我从未有过删除超过 10 个元素的页面。INMHO 通常使用起来display: none比删除一整套节点更快,这就是我不使用removeChild那么多的原因。


对于可能对上面解释的 IE8 内存泄漏更感兴趣的人,我做了另一项测试,似乎在使用 IE8代替添加/删除带有附加事件的子元素时,内存泄漏根本不会出现。innerHTMLappendChild/removeChild显然,Douglas Crockford清除功能(由他建议以防止 IE 中的内存泄漏)在 IE8 中不再需要,至少在使用innerHTML...

编辑感谢下面的 4esn0k 评论)...此外,Douglas Crockford purge 函数在 IE8 上根本不起作用,在他的代码中,var a = d.attributes没有返回在 IE8 上运行时添加的onclick属性(或任何其他onevent属性)(它们确实在 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>
于 2010-09-08T12:43:59.697 回答
2

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

StackOverflow 上有一个类似的帖子:你知道什么可能导致 JavaScript 中的内存泄漏吗?

于 2010-01-04T14:49:14.223 回答