简体   繁体   English

node.js 子进程 object 生命周期

[英]node.js child process object lifecycle

Normally, Javascript variables defined in a function with keyword 'var' should be function-scoped.通常,使用关键字“var”在 function 中定义的 Javascript 变量应该是函数范围的。 But I am confused about a situation related with node.js child process.但我对与 node.js 子进程相关的情况感到困惑。 I have two files, app.js (which is the main file) and child.js (which is the execution script for the child process):我有两个文件,app.js(这是主文件)和 child.js(这是子进程的执行脚本):

// app.js // 应用程序.js

const { fork } = require('child_process');

function bar() {
  var child = fork(`${__dirname}/child.js`); 

  child.on('message', msg => {
    console.log("fib(46) = " + msg);
  });
}

bar();
gc(); // force the garbage collection

// child.js, computationally intensive task, takes tens of seconds to get finished // child.js,计算密集型任务,需要几十秒才能完成

function fib(n) {
  return n < 2 ? 1 : fib(n - 1) + fib(n - 2);
}

var result = fib(46);

process.send(JSON.stringify(result));

I was expecting this piece of code may throw some exceptions because the variable 'child' is a local object created in function bar().我期待这段代码可能会引发一些异常,因为变量“child”是在 function bar() 中创建的本地 object。 It's supposed to be garbage-collected as the function bar() finishes execution.当 function bar() 完成执行时,它应该被垃圾收集。 The event handler registered for receiving child process messages is just kept in the hash table of 'child' object (child object is also an instance of EventEmitter based on docs of node.js child process module), so those hash tables should also be garbage collected as the local 'child' object being reclaimed. The event handler registered for receiving child process messages is just kept in the hash table of 'child' object (child object is also an instance of EventEmitter based on docs of node.js child process module), so those hash tables should also be garbage collected as正在回收的本地“孩子”object。

But the real situation is that tens of seconds later, when the child process finishes calculating fib(46) and sending back the result through process.send, the parent process successfully emits the event and finally gets the registered event handler triggered:但真实的情况是,几十秒后,当子进程计算完 fib(46) 并通过 process.send 发回结果时,父进程成功发出事件,最终触发注册的事件处理函数:

$ node --expose-gc.\app.js $节点--expose-gc.\app.js

fib(46) = 2971215073 fib(46) = 2971215073

So, it looks like the child process object (that object pointing by the local variable 'child') is still in the memory?因此,看起来子进程 object(即 object 指向局部变量“child”)仍在 memory 中? Or that child process object is referenced internally by node.js child process module, so it can not be garbage collected before the end of the child process?或者那个子进程object被node.js子进程模块内部引用了,所以在子进程结束前不能进行垃圾回收? I really need somebody to help me clarify the situation.我真的需要有人帮我澄清一下情况。

Garbage collection can collect something and recycle its memory ONLY when there is no other code that can reach or use or reference that variable.只有在没有其他代码可以访问或使用或引用该变量时,垃圾收集才能收集某些东西并回收其 memory。 Sometimes that situation occurs when a function declares a local variable and then the function executes and returns, but not always.有时当 function 声明一个局部变量然后 function 执行并返回时会发生这种情况,但并非总是如此。

If there are asynchronous operations running (and your child process is an asynchronous operation) and event handlers or callbacks declared within that function scope and those callbacks/events could still be called, then the reachable variables in that function scope cannot be garbage collected until they are truly not reachable any more which, in your case, may be long, long after the function has already executed and returned because that lifetime is associated with the lifetime of the child process, not with the lifetime of the function execution. If there are asynchronous operations running (and your child process is an asynchronous operation) and event handlers or callbacks declared within that function scope and those callbacks/events could still be called, then the reachable variables in that function scope cannot be garbage collected until they在您的情况下,确实无法再访问,这可能在 function 已经执行并返回之后很长时间,因为该生命周期与子进程的生命周期相关联,而不是与 function 执行的生命周期相关联。

In your specific case, because the child object can still emit events long after the function has returned, then then that child object and anything else that its event handlers may access cannot be garbage collected until the child object itself is GCed or until some other situation tells the garbage collector that that event handler can't be called any more. In your specific case, because the child object can still emit events long after the function has returned, then then that child object and anything else that its event handlers may access cannot be garbage collected until the child object itself is GCed or until some other situation告诉垃圾收集器不能再调用该事件处理程序。

So, keep in mind that in Javascript, local variables in a function do not go into a strict stack frame that is 100% recycled as soon as the function returns. So, keep in mind that in Javascript, local variables in a function do not go into a strict stack frame that is 100% recycled as soon as the function returns. Instead, they are properties on a scope object and each individual property on that scope object can only be garbage collected when it is no longer reachable by any active code.相反,它们是 scope object 和 scope ZA8CFDE6331BD59EB2AC66F8911ZC4 上的每个单独属性的属性。 So, it's possible for some things in a scope object to get garbage collected because they aren't referenced in any code that can still be called while other things on the scope object cannot yet be garbage collected because there are callbacks declared within that function scope that may still reference some of those variables declared within that function. So, it's possible for some things in a scope object to get garbage collected because they aren't referenced in any code that can still be called while other things on the scope object cannot yet be garbage collected because there are callbacks declared within that function scope可能仍然引用在 function 中声明的一些变量。 The same rules apply to either a function-scoped or a block-scoped variable as a function scope is just a larger block than a block scope - they now work pretty much the same.相同的规则适用于函数范围或块范围的变量,如 function scope 只是比块 scope 更大的块 - 它们现在的工作原理几乎相同。

Here's a fairly simple example:这是一个相当简单的例子:

function run() {
    let total = 0;
    let msg = "About to start timer";
    console.log(msg);

    const timer = setInterval(() => {
        ++total;
        if (total >= 50) {
            console.log(total);
            clearInterval(timer);
        }
    }, 50);
}

run();

In this code, the local variable msg is available for GC as soon as the function run() exits.在这段代码中,只要 function run()退出,局部变量msg就可用于 GC。

The variable total is not available for GC until after the clearInterval() is called and that final timer callback finishes.在调用clearInterval()并且最终计时器回调完成之前,变量total不可用于 GC。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM