NodeJS 内存泄漏:什么被归类为闭包中的引用

NodeJS Memory Leaks: What classifies as a reference in a closure

提问人:jjordan 提问时间:3/15/2023 更新时间:3/15/2023 访问量:43

问:

我知道在某些情况下,如果闭包中存在引用,则对象可以避免垃圾回收。

引用是否意味着需要将对象的引用分配给某物?或者调用/获取对象的属性是否也算作引用?

例如,以下内部函数是否会在闭包中创建对对象的引用?

const someObject = {
  myProp: 123, 
  callable: () => console.log('hello!')
}

function outer() {
  const innerAssign = () => {
     const innerVar = someObject.myProp;  // does this create reference in closure?
  }

  const innerCall = () => {
     someObject.callable();  // does this create reference in closure?
  }

  const innerRef = () => {
    const newRef = someObject;  // this surely creates a reference in closure
  }
}

此外,创建/使用对象属性键数组是否会创建对原始对象的引用?

例如

const keys = Object.keys(someObject);

另一个问题:当在新作用域中创建对现有对象的另一个引用时,会在堆上为该对象分配额外的内存 - 这是正确的吗?

节点 .js 内存泄漏 闭包

评论

0赞 jfriend00 3/15/2023
对象键本身只是独立的字符串或符号。他们没有任何关于他们来自的物体的参考。
0赞 jfriend00 3/15/2023
问题的其他部分是指对象方法中使用的对象属性。属性永远不会独立于它们所在的对象进行垃圾回收。因此,这里重要的是谁对对象本身有引用。由于如果没有人引用对象,就无法调用方法,因此通常会为您处理事情。如果没有人对该对象有引用,那么没有人可以调用它的任何方法,因此该对象可用于 GC。如果有人引用了该对象,则它不会被 GCed。
0赞 jjordan 3/15/2023
因此 (1) 如果将对象的属性赋给闭包中的变量,则它不会创建对对象的引用,并且 (2) 如果在闭包中调用对象的方法,则会创建对对象的引用。这是正确的吗?
0赞 jfriend00 3/15/2023
嗯,这要看情况。你的代码有点像一个人为的例子,因为尽管你定义了三个内部函数,但没有代码真正调用它们,所以引擎可能足够聪明,可以完全忽略它们,因为优化器可以完全删除它们。如果它们是可调用的,那么只要它们是可调用的,就不能对任何内容进行 GCed 处理,因为所有内部函数都包含对 的引用。因此,只要任何内部函数可以调用并且可以访问,就不能被 GCed。someObjectsomeObject
0赞 jfriend00 3/15/2023
这三个不同的内部函数都是引用的,所以它们用它做不同的事情并不重要。如果可以调用它们,它们都是一个参考。someObject

答:

1赞 jfriend00 3/15/2023 #1

此外,创建/使用对象属性键数组是否会创建对原始对象的引用?

不,它没有。对象键本身只是独立的字符串或符号。他们没有任何关于他们来自的物体的参考。

问题的其他部分涉及对象方法中使用的对象属性。属性永远不会独立于它们所在的对象进行垃圾回收。因此,这里重要的是谁对对象本身有引用。由于如果没有人引用对象,就无法调用方法,因此通常会为您处理事情。如果没有人对该对象有引用,那么没有人可以调用它的任何方法,因此该对象可用于 GC。如果有人引用了该对象,则它不会被 GCed。

因此 (1) 如果将对象的属性赋给闭包中的变量,则它不会创建对对象的引用,并且 (2) 如果在闭包中调用对象的方法,则会创建对对象的引用。这是正确的吗?

嗯,这要看情况。你的代码有点像一个人为的例子,因为尽管你定义了三个内部函数,但没有代码真正调用它们,所以引擎可能足够聪明,可以完全忽略它们,因为优化器可以完全删除它们。如果它们是可调用的,那么只要它们是可调用的,就不能对任何内容进行 GCed 处理,因为所有内部函数都包含对 的引用。因此,只要任何内部函数可以调用并且可以访问,就不能被 GCed。someObjectsomeObject

这三个不同的内部函数都是引用的,所以它们用它做不同的事情并不重要。如果可以调用它们,它们都是一个参考。someObject

另一个问题:当在新作用域中创建对现有对象的另一个引用时,会在堆上为该对象分配额外的内存 - 这是正确的吗?

目前还不完全清楚您的意思,因为您没有显示特定的代码示例。如果在分配的新作用域中创建变量,则分配的唯一新内存是变量本身。该变量包含指向 的一个副本的指针。没有单独的副本,只是因为在其他范围内有另一个对它的引用。someObjectsomeObjectsomeObject