我应该担心清理Node.js中的大对象还是将其留给垃圾收集器?

最近我遇到了一个node.js API的问题,其中我的内存随着每个请求越来越大。 我正在使用他们的只有512MB内存的免费版本在Heroku上托pipe我的服务器。 在周末获得大量stream量之后,我开始从Heroku中获得超出内存的错误,所以我开始在代码中search内存泄漏,但无济于事。 我没有留下任何东西,一切都应该清理干净,坦率地说,我迷路了。

然而,在做了一些研究后,我发现node.js在达到max-old-space-sizevariables时运行垃圾收集器,并且在64位系统上默认为1024MB。 我把它设置为410(我的可用内存的80%),但不知道我是否应该在代码中处理这个问题? 显然这将是理想的升级我的实例,只是正常的默认上限,但现在不是一个选项。

例:

// lets assume there is some apiGet function // that calls back with a very very large object with // the following structure: // { // status: "success", // statusCode: 200, // messages: [], // data: { users: [ huge array of users ] } // } // we have a manipulateData function that's going // to do some stuff to the returned data and the // call some callback to give the data to the caller function manipulateData(callback) { apiGet(function(error, veryLargeObject) { var users = veryLargeObject.data.users; var usefulUsers = users.map(function(user) { // do some data calculations here and then // return just those properties we needed }); callback(null, usefulUsers) }); } 

所以在这个例子中,一旦操作数据完成运行,如果我理解正确,“veyLargeObject”现在将被设置为垃圾收集,因为没有更多的指针有权访问它(返回的有用用户是一个新的数组由地图创build)。 但这并不一定意味着所有的记忆都是自由的,正确的? 在调用callback之前设置veryLargeObject = null或undefined是明智的吗?

我希望我所问的是有道理的。 基本上来说:将大对象设置为null或undefined时,是不是有意使用它们,或者应该留给垃圾收集器清理? 对于这个问题,如果只有512MB内存而不是8GB内存,这个问题的答案是否会改变?

如果您确定不再需要某个给定的对象,那么将其设置为null是要走的路(请注意,这并不意味着任何链接的对象也将被垃圾回收)。 只有当给定对象的所有引用都设置为null(对象变得无法从代码中的任何位置访问)时,才会收集该对象。

由于node.js使用V8引擎,你可以得到一些关于如何改善垃圾收集的提示V8:垃圾收集之旅 。 如果这还不够,可以按照这些说明强制GC。

只有在某种封闭情况下才需要将variables设置为null ,例如:

 function createClosure(bigData) { var unrelatedVar = 1; doSomethingAsync(function theCallback(err, result) { if (bigData.matches(result)) { ... } }); return function theReturnedFunction() { return unrelatedVar++; }; } 

在V8中,相同级别的闭包共享相同的上下文对象,其中closures了variables的位置。 所有的同级closures然后指向上下文对象,所以它将保持活着,直到所有的function都死了。 所以在这里, theReturnedFunctiontheCallback函数都是相同级别的函数,它们都指向与2个成员相同的上下文对象:bigData和unrelatedVar。 所以只要返回的函数是活着的,即使它不能被引用,bigData也是活着的。

这很容易陷入,因为封闭式variables看起来和局部variables完全一样,而事实上它们就像一个对象的字段(这将使用明确的this.field所以它总是很明显)。 这与在没有使用显式对象的.bigData字段后将其设置为null没有什么不同,但是当它是一个明确的对象时,则很难错过。