JavaScript关闭如何收集垃圾 [英] How JavaScript closures are garbage collected

查看:191
本文介绍了JavaScript关闭如何收集垃圾的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我记录了以下 Chrome bug ,导致了许多严重和不明显的内存泄漏我的代码:

(这些结果使用Chrome开发工具,内存分析器,它运行的GC,然后采取一堆没有垃圾收集的堆快照。)



在下面的代码中, someClass 实例被垃圾收集(好):

  var someClass = function(){}; 

函数f(){
var some = new someClass();
return function(){};
}

window.f_ = f();

但在这种情况下不会被垃圾收集(坏):

  var someClass = function(){}; 

函数f(){
var some = new someClass();
函数unreachable(){一些; }
return function(){};
}

window.f_ = f();



和相应的截图:

< img src =https://i.stack.imgur.com/ZSVf0.pngalt =Chromebug截图>



看来,在这种情况下,如果对象被同一上下文中的任何其他闭包所引用,则不管该闭包本身是否为甚至可以访问。

我的问题是关于在其他浏览器(IE 9 +和Firefox)中关闭的垃圾收集。我对webkit的工具非常熟悉,比如JavaScript堆分析器,但是我对其他浏览器的工具知之甚少,所以我一直无法测试这个。



在这三种情况下,IE9 +和Firefox垃圾收集哪一个 someClass 实例?

解决方案

我在IE9 +和Firefox中测试了这个。

  function f(){
var some = []; (some.length< 1e6){
some.push(some.length);
}
函数g(){some; } //删除这个修复了大量的内存泄漏
return function(){}; //或删除此
}

var a = [];
var interval = setInterval(function(){
var len = a.push(f());
if(len> = 500){
clearInterval(interval) ;
}
},10);

实时网站函数(){}的数组, ,使用最少的内存。



不幸的是,情况并非如此。每一个空的函数都会持有一个数百万个数字的(永远不可达,但不是GC'ed)数组。



Chrome最终会停下来并死亡,Firefox完成之后使用接近4GB的内存,IE越来越慢,直到它显示内存不足。

删除其中一个注释行可以修复所有内容。



似乎所有这三种浏览器(Chrome浏览器,Firefox和IE)都保持每个上下文的环境记录,而不是每个闭包。鲍里斯假设这个决定背后的原因是性能,这似乎很可能,但我不确定如何根据上述实验调用性能。



如果需要一个引用一些(我在这里没有使用它,但想象我做了)的闭包,如果不是

  function g(){some; } 

我使用

  var g =(function(some){return function(){some;};)(some); 

通过将闭包移动到与其他函数不同的上下文中来解决内存问题。 p>

这会让我的生活变得更乏味。

PS出于好奇,我在Java中尝试了这个(使用它在函数中定义类的能力)。 GC的工作原理就是我所希望的Javascript。


I've logged the following Chrome bug, which has led to many serious and non-obvious memory leaks in my code:

(These results use Chrome Dev Tools' memory profiler, which runs the GC, and then takes a heap snapshot of everything not garbaged collected.)

In the code below, the someClass instance is garbage collected (good):

var someClass = function() {};

function f() {
  var some = new someClass();
  return function() {};
}

window.f_ = f();

But it won't be garbage collected in this case (bad):

var someClass = function() {};

function f() {
  var some = new someClass();
  function unreachable() { some; }
  return function() {};
}

window.f_ = f();

And the corresponding screenshot:

It seems that a closure (in this case, function() {}) keeps all objects "alive" if the object is referenced by any other closure in the same context, whether or not if that closure itself is even reachable.

My question is about garbage collection of closure in other browsers (IE 9+ and Firefox). I am quite familiar with webkit's tools, such as the JavaScript heap profiler, but I know little of other browsers' tools, so I haven't been able to test this.

In which of these three cases will IE9+ and Firefox garbage collect the someClass instance?

解决方案

I tested this in IE9+ and Firefox.

function f() {
  var some = [];
  while(some.length < 1e6) {
    some.push(some.length);
  }
  function g() { some; } //removing this fixes a massive memory leak
  return function() {};   //or removing this
}

var a = [];
var interval = setInterval(function() {
  var len = a.push(f());
  if(len >= 500) {
    clearInterval(interval);
  }
}, 10);

Live site here.

I hoped to wind up with an array of 500 function() {}'s, using minimal memory.

Unfortunately, that was not the case. Each empty function holds on to an (forever unreachable, but not GC'ed) array of a million numbers.

Chrome eventually halts and dies, Firefox finishes the whole thing after using nearly 4GB of RAM, and IE grows asymptotically slower until it shows "Out of memory".

Removing either one of the commented lines fixes everything.

It seems that all three of these browsers (Chrome, Firefox, and IE) keep an environment record per context, not per closure. Boris hypothesizes the reason behind this decision is performance, and that seems likely, though I'm not sure how performant it can be called in light of the above experiment.

If a need a closure referencing some (granted I didn't use it here, but imagine I did), if instead of

function g() { some; }

I use

var g = (function(some) { return function() { some; }; )(some);

it will fix the memory problems by moving the closure to a different context than my other function.

This will make my life much more tedious.

P.S. Out of curiousity, I tried this in Java (using its ability to define classes inside of functions). GC works as I had originally hoped for Javascript.

这篇关于JavaScript关闭如何收集垃圾的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆