【问题标题】:Is this nodejs code a circular reference?这个nodejs代码是循环引用吗?
【发布时间】:2013-02-16 02:10:58
【问题描述】:

它们只是 node.js 官方文档的几行代码。

client.on('data', function(data) {
  console.log(data.toString());
  client.end();
});

我认为客户端对象有对回调的引用,回调有对客户端对象的闭包引用。那是对的吗?如果是,为什么鼓励这样做?

【问题讨论】:

  • client 在回调中由于范围而引用了原始客户端,因此除非您重新定义它,否则它不能引用任何其他 client。这不会导致任何范围界定问题,因此可以安全使用。唯一的另一种方法是将客户端作为参数传递(您无法控制框架传递的内容)或在另一个范围内定义客户端,例如 window,这可能会引入更多问题并且没有改进。

标签: javascript node.js memory-leaks closures


【解决方案1】:

是的,这是一个循环引用,但它不是内存泄漏。仅给定这段代码 sn-p,您只有一小部分对象的小图,但是是的,只要您的主程序可以访问 client,所有这些对象将永远不会有资格进行垃圾回收。但是,如果您要设置client = null;,则包括client 对象和匿名事件处理函数在内的对象图将无法从主程序访问,因此有资格进行垃圾回收并因此A-OK。

这种模式本身并不是内存泄漏。如果您要在循环中创建客户端并将对所有客户端的引用保存在数组或对象中,而无需处理过时客户端的代码,那么是的,这将是内存泄漏。

【讨论】:

  • 谢谢。可能有更复杂的循环引用。我可以说两个相互引用的对象,无论是直接的还是间接的,它们都会被 V8 垃圾收集吗?只有当其中一个被第三个对象引用时,才会有内存泄漏?
  • 没错。如果从代码的可运行部分无法访问整个大型对象图,则该整个图有资格进行垃圾回收。上述大多数典型代码模式都不会导致泄漏。使用对象或数组作为缓存、映射、集合等时要保持警惕,因为它们可能是添加但从不删除错误泄漏的候选对象。
【解决方案2】:

这是正确的。 node.js 中的事件发射器将其侦听器存储在私有 _listeners 属性中。 您的处理程序函数使用client 作为封闭变量,这不是绝对必要的,因为所有处理程序都使用事件发射器作为this 引用来调用。

但是,使用 this 而不是 client 并不会改变 client 在闭包中的事实,它只是提示 V8 取消对闭包的引用,因为它没有被使用。

即使是从闭包中使用,V8 也有足够的逻辑来处理这种循环引用并正确地从内存中释放它们。

【讨论】:

  • 谢谢。所以我们不应该担心这种模式中的循环引用?
猜你喜欢
  • 1970-01-01
  • 2017-11-26
  • 1970-01-01
  • 2016-09-20
  • 1970-01-01
  • 2016-11-17
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多