Node.js (v8) 垃圾收集器如何工作?
Posted
技术标签:
【中文标题】Node.js (v8) 垃圾收集器如何工作?【英文标题】:How does the Node.js (v8) Garbage Collector work? 【发布时间】:2014-02-05 10:19:10 【问题描述】:我已经对我的 node.js 应用程序进行了一些测试,以寻找我的代码应该做的内存泄漏。我运行的脚本在我看来应该会泄漏内存,但我对结果感到惊讶。
redisClient.on('message', initRequest);
function onSuccess(self, json)
console.dir(json);
function initRequest(channel, message)
var request = new RequestObject(
redisMessage: message
);
request.on('success', onSuccess);
redisClient 每秒发出几个“消息”事件。这意味着initRequest
函数被经常调用。每次在内存中创建request
对象时,函数onSuccess
都会绑定到它的“成功”事件。
我假设(但在这里我可能错了),只要有监听器(在这种情况下为onSuccess
)绑定到这个对象,它就不能被垃圾收集。然后我想,内存使用量会增加,因为内存不会被释放。
作为这种潜在泄漏的解决方案,我想使用.once
而不是.on
,因为这会解除监听器的绑定并且对象可能会被垃圾回收。
我已经使用 pmap 测试了这两种情况(比较 .on
和 .once
以及另一种在此不值一提的情况),我没有发现很大的不同.
总结一下我有2个问题:
这种正常的 GC 行为是在某些时间间隔内清理内存,还是在达到某个阈值后而不是连续清理?
我是否正确地假设带有.on
的示例代码应该泄漏内存,而我在内存消耗图中没有看到?
【问题讨论】:
一些想法...对于第一个问题,是的,这很正常。垃圾收集循环运行。当您不再引用某些内存时,它可能会被垃圾收集,但没有迹象表明何时会发生这种情况。至于第二个问题,我预计那里也会发生内存泄漏。古玩以查看为什么它在图表中不可见的答案。 为了清楚起见,你能用 .once 显示代码吗?我假设您是在 redisClient 上完成的,但目前只是猜测。另外,我确实在 1 中看到了更高的使用率。红线..是“泄漏”吗?一个传奇会很好。由于 onSuccess 在所有 initRequest 之间共享,因此将使用极少的额外内存,因此如果您的请求在达到几百万之前全部完成,我预计不会有更高的峰值。 你用的是哪个redis客户端模块?我搜索了RequestObject
并没有找到任何有趣的东西。
【参考方案1】:
据我所知,请求对象应该只存在于 initRequest 函数中,因此应该在函数终止时标记为垃圾回收。
【讨论】:
【参考方案2】:1: 是的:-)
2:一般来说,使用事件侦听器时的内存泄漏是阻止了正在侦听的对象被垃圾回收,因为发出的对象保留了对它的引用。
因此,在您的代码中,onSuccess
函数将被您的 request
对象引用。但是,onSuccess
只是一个函数,它被用作所有请求对象的侦听器,因此不会导致内存累积。
旁注:我不知道 redisClient
和 RequestObject
的内部结构,但在我看来,request
似乎也将在 initRequest
函数完成后立即进行垃圾收集,这可能是在调用其任何侦听器之前。
【讨论】:
我的担忧似乎来自关于谁在引用谁的错误假设。现在我明白事件发射器是在引用侦听器而不是相反的方式。以上是关于Node.js (v8) 垃圾收集器如何工作?的主要内容,如果未能解决你的问题,请参考以下文章
Node.js 的可伸缩性是不是会因为高负载下的垃圾收集而受到影响?