何时在Node.js V8中分配和编译闭包

When are closures allocated and compiled in Node.js V8?

本文关键字:分配 编译 闭包 V8 Node js 何时      更新时间:2024-04-16

根据我目前对VM及其行为的假设,我认为每次调用闭包的定义时都会对其进行分配和编译;与在闭包外声明的函数相比,闭包只分配和编译一次(因为它们被放置在某个地方,所以它们的定义只命中一次)。这个假设正确吗?

所以,如果我在socket.on('data', function (data) {...})中有一个闭包,V8每次套接字接收数据时都会分配新的内存(并可能重新编译)闭包

我认为闭包在每次定义被命中时都会被分配和编译

不是。闭包被编译一次,但每次它们的定义被命中时都被分配。最重要的是,您必须区分分配和编译。

  • 每个函数的代码(即在源代码中具有相同位置)只编译一次,即使函数在不同的环境中被实例化多次也是如此
    对每个实例化进行编译是毫无意义的,就像对每个调用进行编译一样(不过,"解释器"就是这么做的,边界是流动的,例如,对于不在第一次调用之前发生的懒惰编译)
    如果代码成为优化候选,或者优化失败,必须取消优化,则可能会再次编译代码(使用较慢但更复杂的编译器);但这不是重点。

  • 每个函数在其定义被命中时都会被分配/实例化,这与本地函数(嵌套在其他函数中)特别相关
    然而,非闭包函数的分配成本为零,因为不需要存储环境指针,也不需要实例对象。

所以,如果我在socket.on('data', function (data) {...})中有一个闭包,V8在每次套接字接收到数据时都会分配新的内存(并可能重新编译)闭包?

不是function (data) {…},它只实例化一次并传递给on调用。

但是,是的,如果您有一个在部分中实例化的闭包,那么它将在每次接收数据和调用处理程序时分配一些内存。但无需担心这一点,内存分配既便宜又快速。

如果你正在寻找技术细节,我建议你阅读http://mrale.ph/blog/2012/09/23/grokking-v8-closures-for-fun.html(尽管它已经有几年的历史了)。

根据我目前对虚拟机及其行为的假设,我认为每次调用闭包的定义时都会对其进行分配和编译;

右侧

与在闭包外声明的函数相反,闭包只分配和编译一次。

false,每次它们的定义被命中时也会编译这些,但它们通常被放在一个地方,在那里它们的定义只被命中一次
闭包被设计为多次定义,每次都包含不同的变量/值
这就是我们区分这是一个简单/匿名函数还是一个闭包的方法

每当套接字接收到数据时,V8都会分配新的内存

不,这个匿名函数只编译一次,然后传递给事件处理程序。事件处理程序现在有一个对此函数的引用,并在每次接收数据时调用它。

在添加事件侦听器时,此示例中的定义也只命中一次。