javascript 使用 node.js 进行垃圾收集

声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow 原文地址: http://stackoverflow.com/questions/5326300/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me): StackOverFlow

提示:将鼠标放在中文语句上可以显示对应的英文。显示中英文
时间:2020-10-25 16:48:45  来源:igfitidea点击:

garbage collection with node.js

javascriptnode.jsv8

提问by Vishnu

I was curious about how the node.js pattern of nested functions works with the garbage collector of v8. here's a simple example

我很好奇嵌套函数的 node.js 模式如何与 v8 的垃圾收集器一起工作。这是一个简单的例子

readfile("blah", function(str) {
   var val = getvaluefromstr(str);
   function restofprogram(val2) { ... } (val)
})

if restofprogram is long-running, doesn't that mean that str will never get garbage collected? My understanding is that with node you end up with nested functions a lot. Does this get garbage collected if restofprogram was declared outside, so str could not be in scope? Is this a recommended practice?

如果 restofprogram 是长时间运行的,那是不是意味着 str 永远不会被垃圾收集?我的理解是,使用节点,您最终会得到很多嵌套函数。如果在外部声明了 restofprogram,这是否会被垃圾收集,因此 str 不能在范围内?这是推荐的做法吗?

EDITI didn't intend to make the problem complicated. That was just carelessness, so I've modified it.

编辑我不打算让问题复杂化。那只是粗心大意,所以我修改了它。

回答by Vyacheslav Egorov

Simple answer: if value of the stris not referenced from anywhere else (and stritself is not referenced from restofprogram) it will become unreachable as soon as the function (str) { ... }returns.

简单的答案:如果str没有从其他任何地方引用 的值(并且str没有从 引用restofprogram它本身),它将在function (str) { ... }返回后立即变得无法访问。

Details: V8 compiler distinguishes real localvariables from so called contextvariables captured by a closure, shadowed by a with-statement or an evalinvocation.

详细信息:V8 编译器将真正的局部变量与由闭包捕获的、由with语句或调用隐藏的所谓上下文变量区分开来。 eval

Local variables live on the stack and disappear as soon as function execution completes.

局部变量存在于堆栈中,并在函数执行完成后立即消失。

Context variables live in a heap allocated context structure. They disappear when the context structure dies. Important thing to note here is that context variables from the same scope live in the samestructure. Let me illustrate it with an example code:

上下文变量存在于堆分配的上下文结构中。当上下文结构消失时,它们就会消失。这里要注意的重要一点是,来自同一作用域的上下文变量存在于同一结构中。让我用一个示例代码来说明它:

function outer () {
  var x; // real local variable
  var y; // context variable, referenced by inner1
  var z; // context variable, referenced by inner2

  function inner1 () {
    // references context 
    use(y);
  }

  function inner2 () {
    // references context 
    use(z);
  }

  function inner3 () { /* I am empty but I still capture context implicitly */ } 

  return [inner1, inner2, inner3];
}

In this example variable xwill disappear as soon as outerreturns but variables yand zwill disappear only when bothinner1, inner2andinner3die. This happens because yand zare allocated in the same context structure and all three closures implicitly reference this context structure (even inner3which does not use it explicitly).

在这个例子中变量x将尽快消失outer的回报,但变量y,并z只有当将消失两个inner1inner2inner3死。发生这种情况是因为yz分配在相同的上下文结构中,并且所有三个闭包都隐式地引用了这个上下文结构(即使inner3没有显式使用它)。

Situation gets even more complicated when you start using with-statement, try/catch-statement which on V8 contains an implicit with-statement inside catch clause or global eval.

当您开始使用with-statement、try/catch-statement 时,情况会变得更加复杂,它们在 V8 上在 catch 子句或 global 中包含一个隐含的with-statement eval

function complication () {
  var x; // context variable

  function inner () { /* I am empty but I still capture context implicitly */ }

  try { } catch (e) { /* contains implicit with-statement */ }

  return inner;
}

In this example xwill disappear only when innerdies. Because:

在这个例子中x只会在inner死亡时消失。因为:

  • try/catch-contains implicit with-statement in catch clause
  • V8 assumes that any with-statement shadows allthe locals
  • try / catch语句-包含隐在catch子句语句来
  • V8 假设 any with-statement 会影响所有本地人

This forces xto become a context variable and innercaptures the context so xexists until innerdies.

这会强制x成为上下文变量并inner捕获上下文,x直到inner死亡为止。

In general if you want to be sure that given variable does not retain some object for longer than really needed you can easily destroythis link by assigning nullto that variable.

一般来说,如果您想确保给定的变量不会保留某个对象的时间超过实际需要的时间,您可以通过分配给该变量来轻松破坏此链接null

回答by rsp

Actually your example is somewhat tricky. Was it on purpose? You seem to be maskingthe outer valvariable with an inner lexically scoped restofprogram()'s valargument, instead of actually using it. But anyway, you're asking about strso let me ignore the trickiness of valin your example just for the sake of simplicity.

其实你的例子有点棘手。是故意的吗?您似乎用内部词法范围的 restofprogram()参数掩盖了外部val变量val,而不是实际使用它。但无论如何,您要问的是,为了简单起见,str让我忽略val您示例中的棘手问题。

My guess would be that the strvariable won't get collected before the restofprogram() function finishes, even if it doesn't use it. Ifthe restofprogram() doesn't use strandit doesn't use eval()and new Function()then it couldbe safely collected but I doubt it would. This would be a tricky optimization for V8 probably not worth the trouble. If there was no evaland new Function()in the language then it would be much easier.

我的猜测是str变量在 restofprogram() 函数完成之前不会被收集,即使它不使用它。如果restofprogram() 不使用str并且不使用eval()new Function()可以安全地收集它,但我怀疑它会。这对 V8 来说是一个棘手的优化,可能不值得麻烦。如果没有evalnew Function()在语言中,那么它会容易得多。

Now, it doesn't have to mean that it would never get collected because any event handler in a single-threaded event loop should finish almost instantly. Otherwise your whole process would be blocked and you'd have bigger problems than one useless variable in memory.

现在,这并不一定意味着它永远不会被收集,因为单线程事件循环中的任何事件处理程序都应该几乎立即完成。否则你的整个过程将被阻塞,你会遇到比内存中一个无用变量更大的问题。

Now I wonder if you didn't mean something else than what you actually wrote in your example. The whole program in Node is just like in the browser – it just registers event callbacks that are fired asynchronously later after the main program body has already finished. Also none of the handlers are blocking so no function is actually taking any noticeable time to finish. I'm not sure if I understood what you actually meant in your question but I hope that what I've written will be helpful to understand how it all works.

现在我想知道您的意思是否与您在示例中实际编写的内容无关。Node 中的整个程序就像在浏览器中一样——它只是注册事件回调,这些回调在主程序主体完成后异步触发。此外,没有任何处理程序正在阻塞,因此实际上没有任何功能需要花费任何明显的时间来完成。我不确定我是否理解您在问题中的实际意思,但我希望我所写的内容有助于理解这一切是如何运作的。

Update:

更新:

After reading more info in the comments on how your program looks like I can say more.

在阅读有关您的程序外观的评论中的更多信息后,我可以说更多。

If your program is something like:

如果你的程序是这样的:

readfile("blah", function (str) {
  var val = getvaluefromstr(str);
  // do something with val
  Server.start(function (request) {
    // do something
  });
});

Then you can also write it like this:

那么你也可以这样写:

readfile("blah", function (str) {
  var val = getvaluefromstr(str);
  // do something with val
  Server.start(serverCallback);
});
function serverCallback(request) {
  // do something
});

It will make the strgo out of scope after Server.start() is called and will eventually get collected. Also, it will make your indentation more manageable which is not to be underestimated for more complex programs.

它将str在调用 Server.start() 后超出范围并最终被收集。此外,它还将使您的缩进更易于管理,对于更复杂的程序来说,这一点不容小觑。

As for the valyou might make it a global variable in this case which would greatly simplify your code. Of course you don't have to, you can wrestle with closures, but in this case making valglobal or making it live in an outer scope common for both the readfile callback and for the serverCallback function seems like the most straightforward solution.

至于val在这种情况下,您可以将其设为全局变量,这将大大简化您的代码。当然,您不必这样做,您可以解决闭包问题,但在这种情况下,使val全局或使其位于 readfile 回调和 serverCallback 函数通用的外部作用域中似乎是最直接的解决方案。

Remember that everywhere when you can use an anonymous function you can also use a named function, and with those you can choose in which scope do you want them to live.

请记住,在任何地方,当您可以使用匿名函数时,您也可以使用命名函数,并且您可以选择希望它们存在于哪个范围内。

回答by dhruvbird

My guess is that str will NOT be garbage collected because it can be used by restofprogram(). Yes, and str should get GCed if restofprogram was declared outside, except, if you do something like this:

我的猜测是 str 不会被垃圾收集,因为它可以被 restofprogram() 使用。是的,如果在外部声明了 restofprogram,则 str 应该被 GCed,除非您执行以下操作:

function restofprogram(val) { ... }

readfile("blah", function(str) {
  var val = getvaluefromstr(str);
  restofprogram(val, str);
});

Or if getvaluefromstr is declared as something like this:

或者,如果 getvaluefromstr 被声明为这样的:

function getvaluefromstr(str) {
  return {
    orig: str, 
    some_funky_stuff: 23
  };
}

Follow-up-question: Does v8 do just plain'ol GC or does it do a combination of GC and ref. counting (like python?)

后续问题:v8 是只执行普通 GC 还是执行 GC 和 ref 的组合。计数(像蟒蛇?)