在express/node.js API中高效的服务器端JavaScript内存管理

11

概述

我过去读了一些关于JavaScript内存管理的文章,并且知道DOM循环引用等问题。

然而,当这个问题转化到服务器端JavaScript环境中,比如node.js,特别是在express上编写API时,我仍然有点不安。


使用这个示例文件(让我们称之为server.js)

var npm_moduleA = require('npmA')({ someInitArg : 'blah' }),
    app = express.createServer();

app.get('/api/foo', function (req, res) {

    var result = npm_moduleA.doSomething();
    res.send(result);

});

app.get('/api/bar', function (req, res) {

    var npm_moduleB = require('npmB')({ someInitArg : 'blah' }),
        result = npm_moduleB.doSomethingElse();

    res.send(result);

});

问题(假设这是一个高负载网站)

  1. npm_moduleA 的生命周期是什么?它在服务器启动时被创建,但GC何时介入它(如果有的话) - 我猜测它从未被触及,因为它在全局范围内。

  2. 在'/api/bar/'中,每个请求后是否应该删除npm_moduleB还是只交给 GC 处理。

  3. 全局初始化npm_moduleA比重复实例化(和可能的删除)npm_moduleB效率显着更高吗?


参考资料

1个回答

9
由于Node.js不会为每个调用创建和销毁运行上下文,因此无论是npm_moduleA还是npm_moduleB都会一直存在(在缓存中),直到您关闭服务器。
事实上,无论在哪里引用模块,它只是获取一个指向模块入口点的指针,在运行时不会实例化任何东西。
这里有一个例子:
index.js
var t = require('./module.js');
t.value = 10;

function test() {
  var t2 = require('./module.js');
  console.log(t2.value);
}

test();

module.js

module.exports = {};

控制台输出:

10

在这种情况下,只需在全局范围内放置您的require()一次。不要在回调函数中执行require(),因为require()需要做一些文件名解析工作,在任何方面上与全局范围内的require()没有区别。
但是,如果您要实例化一个类new SomeClass(),那么它的位置就很重要了。

谢谢回复 - 你在示例代码中指出了一个错误...我的requires应该还要显示一个类的实例化(所以是require('blah')(/* some init args */)而不仅仅是需要源文件)。我已经更新了我的代码,这可能会影响你的一些答案。 - isNaN1247
1
@beardtwizzle:我的观点仍然成立,无论你在哪里请求某些东西,它只会返回一个指向缓存条目的指针。如果你要使用在模块中导出的函数,它将驻留在缓存中,并且在服务器关闭之前不会被释放。 - xiaoyi
如果您有一个静态初始化参数,并且该函数可以在请求期间共享,则只需保留实例全局。这应该具有更好的性能,您可以想象任何时候内存使用量都是恒定的(因为请求是串行响应的,请尝试不要关闭连接,那么就不会为其他客户端提供服务)。如果您的服务器非常繁忙,第二种模式将由于创建/销毁对象而存在一些性能问题,并且无法节省大量内存使用。 - xiaoyi

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接