2013-03-01 60 views
1

它们只是来自node.js官方文档的几行内容。这个nodejs代码是循环引用吗?

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

我觉得客户端对象引用了回调,回调函数对客户端对象有一个闭包引用。那是对的吗?如果是的话,为什么这是鼓励?

+0

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

回答

2

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

这种模式本身并不是内存泄漏。如果你要在一个循环中创建客户端,并在一个数组或对象中保留一个对所有这些客户端的引用,并且没有代码来处理陈旧的客户端,那么是的,那就是内存泄漏。

+0

谢谢。可能会有更复杂的循环引用。我可以说两个互相引用的对象,无论是直接的还是间接的,它们都会被V8垃圾回收?只有当其中一个被第三个对象引用时,才会有内存泄漏? – 2013-03-02 08:31:29

+0

这是正确的。如果从代码的可运行部分中无法访问整个大对象图,那么整个图就有资格进行垃圾回收。大多数典型的代码模式(如上述)不会导致泄漏。在使用对象或数组作为缓存,地图,集合等时应保持警惕,因为这些可能是添加但从不删除错误泄漏的候选对象。 – 2013-03-02 15:09:45

1

这是正确的。 node.js中的事件发射器将其监听器存储在私有_listeners属性中。 您的处理程序函数使用client作为封闭变量,这并非严格必要,因为所有处理程序都使用事件发件人作为this引用进行调用。

然而,使用this代替client不会改变的事实,client是在封闭的,因为它不使用它只是暗示V8取消对它的引用从封闭。

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

+1

谢谢。所以我们不应该担心这种模式中的循环引用? – 2013-03-02 08:18:45