为什么这段代码消耗内存并且没有完全回收?

时间:2011-04-14 06:56:18

标签: javascript garbage-collection xmlhttprequest

我有一个简单的JavaScript代码,它在无限运行时消耗内存。内存消耗由Google Chrome内存分析器监控。

  setInterval(function(){
     var xhr = new XMLHttpRequest();
     xhr.open('GET', 'json.txt', true);
     xhr.onreadystatechange = function() {
        if(this.readyState == 4 && this.status == 200) {
           console.log(this.responseText);
        }
     };
     xhr.send('');
  }, 500);

上面的代码示例和json.txt的Html文件托管在我的本地服务器上,获取文件的时间不超过500毫秒(总是大约7-10毫秒)。

在很长一段时间内,内存图看起来就像那样 Initial memory consumption graph

编辑一小时工作后的同一个Chrome窗口 Graph after a hour of work

修改 从长远来看(小时)并非所有内存都被回收,图表仍然在升序。 我理解为什么消耗了内存,我不明白为什么没有完全回收

修改 这就是我如何减少内存泄漏

  var callback = function(){
      if(this.readyState == 4 && this.status == 200) {
          console.log(this.responseText);
      }
  } 

  setInterval(function(){
     var xhr = new XMLHttpRequest();
     xhr.open('GET', 'json.txt', true);
     xhr.onreadystatechange = callback;
     xhr.send('');
  }, 500);

这种改进允许不将回调的闭包链接到xhr var。

5 个答案:

答案 0 :(得分:6)

对于一个你重复加载json.txt的内容,这将需要一些内存。除此之外,XHR本身也可能需要一些记忆。然而,我并不认为这是一个很大的问题,因为无论如何记忆似乎都被收回了。

答案 1 :(得分:0)

为什么不应该呢?至少 var xhr = new XMLHttpRequest(); 必须在每次迭代时消耗内存并由GC收集(可能在图表中显示)。

答案 2 :(得分:0)

如果请求 - 响应周期超过指定的时间间隔,肯定会有一些内存开销。

因为只有在请求完成后才会释放内存(成功或错误)。

答案 3 :(得分:0)

由于使用了console.log,因此很可能没有完全回收内存。我假设在引擎盖下,控制台会将内容添加到内部数组,或者可能是一个字符串,并且由于您要向其中添加大块数据,并且从不从中删除,因此GC将永远不会清除它,而应用程序是运行。尝试注释掉该语句,看看它是否会改变内存使用情况。用于创建XMLHttpRequest的内存最终由GC释放,因为在请求完成后对它的引用将变为孤立,但是控制台是一个全局变量,在页面可用时仍然保留在范围内。

答案 4 :(得分:0)

我想这个间隔不是在真空中设置的。您传入setInterval的函数可以访问它所定义的词法范围。这意味着它周围的每个变量总是可以在垃圾收集器的眼中访问,即使您没有在函数中使用这些变量。垃圾收集器永远不会清理它。在一个更卫生的环境中定义函数可能会更好,因为它不会对任何大小的变量进行闭包访问。

编辑:抱歉,我会尽量让自己更清楚。这与XHR无关 - 你可以在setInterval函数中放置任何东西(甚至没有),如果你想要清理它的词法范围中的某些变量,它仍然会泄漏。您只需要确保setInterval函数没有对要清理的任何变量的闭包访问。例如:

(function() {
  var a = readFile('a-very-big-file.txt');

  setInterval(function() {
    console.log('im leaking!');
  }, 500);
})();

那会泄漏。即使setInterval没有做任何特别有意义的事情,它仍然可以访问“a”,垃圾收集器将其视为可达。