【发布时间】:2013-05-02 18:33:53
【问题描述】:
function(foo, cb) {
var bigObject = new BigObject();
doFoo(foo, function(e) {
if (e.type === bigObject.type) {
cb();
// bigObject = null;
}
});
}
上面的例子展示了一个经典的、偶然的(或者可能不是)内存泄漏的闭包。 V8 垃圾收集器无法确定删除 bigObject 是否安全,因为它正在用于可以多次调用的回调函数中。
一种解决方案是在回调函数中的作业结束时将bigObject 设置为null。但是如果你使用了很多变量(想象一下有n 变量,比如bigObject,并且它们都在回调中使用),那么清理这将成为一个丑陋的问题。
我的问题是:还有其他方法可以清理那些使用过的变量吗?
编辑 这是另一个(真实世界)示例:所以我从 mongodb 获取应用程序并将其与其他应用程序进行比较。来自 mongodb 的回调使用从该回调中定义的变量应用程序。从 mongodb 获得结果后,我也将它作为回调返回(因为它都是异步的,我不能只写 return )。所以实际上可能会发生我将回调一直传播到源......
function compareApplications(application, condition, callback) {
var model = database.getModel('Application');
model.find(condition, function (err, applicationFromMongo) {
var result = (applicationFromMongo.applicationID == application.applicationID)
callback(result)
}
}
【问题讨论】:
-
让我问你这个 - 为什么这是一个问题?
change处理程序被多次调用。那么,除非您取消绑定change事件,否则您(或 GC)将如何知道何时真正结束使用bigObject?您似乎想要一个bigObject实例,以便处理程序可以比较类型。您将其实例化一次,这样每次处理程序运行时都会减少负载。如果你想清理它,每次都在处理程序中实例化它,或者期望它“泄漏”内存,因为它就是这样工作的。 -
用 .one() 代替 .on() 怎么样?
-
请注意,我不使用 jQuery,也不绑定或注册某些事件。我只是将回调函数传递给另一个。我使用 NODE.JS !
-
我担心的是,我可能有一系列回调......例如,业务函数调用数据函数调用 mongodb,并且这些函数之间的所有通信都在回调中。也许来自 mongodb 的回调确实可以清除所有内容,但业务和数据层中的这些其他回调是什么。我想 GC 只看到回调,而他看不到他下面的东西。我还没有对泄漏进行分析,但我可以清楚地看到我的 node.js 工作人员使用了太多的 rss(RAM) 内存。
-
是的,但是在每一种回调中(在业务层或数据层)你都可以有一个闭包,你真的确定他们会清理吗? ...听听这个例子。在代码的其他部分中,我也从数据库中读取但在流中。我有 stream.on(data){...} 事件,每次当我收集 1000 条记录时,我都会为业务层启动回调(在我的第一篇文章中的示例中,它将是这个:回调(结果))...业务层回调函数的实现实际上是一个闭包,它工作得很好。为什么 GC 在第一次回调后没有清理该闭包?
标签: javascript node.js memory-leaks closures