如何追踪Node.js和Express内存泄漏?

时间:2014-08-28 13:50:47

标签: node.js memory heroku express memory-leaks

我们正在使用看似简单的Node.js和Express服务器为Angular.js项目提供服务,您可以在下面看到。它背后的想法是,如果客户端要求的服务器上存在一个文件,比如main.css,那么它将由快速静态中间件返回。否则我们假设它是一个像/ account这样的有角度的路由,我们返回index.html文件,以便Angular可以接管。

附上你可以看到Heroku上的内存尖峰然后Heroku正在杀死服务器并重新启动它。然后它的峰值再次出现......

Memory pattern

这是服务器:

    var newrelic = require('newrelic')
      , fs = require('fs')
      , express = require('express')
      , app = express()
      , ENV = process.env.NODE_ENV || 'development'
      , ENV_PROD = ENV == 'production'
      , port = process.env.PORT || 8080;

    console.log('ENV: ' + ENV);

    // force ssl
    app.use(function(req, res, next){
        if (ENV_PROD) {
            var protocol = req.get('x-forwarded-proto');
            if (protocol != 'https') {
                res.redirect(301, 'https://' + req.get('host') + req.url);
            } else {
                res.header('Strict-Transport-Security', 'max-age=31536000');
                next();
            }
        } else {
            next();
        }
    });

    // set default headers
    app.use(function(req, res, next){
        var cache = ENV_PROD ? 3600 : 0;
        res.set('Cache-Control', 'public, max-age='+cache);
        res.set('Vary', 'Accept-Encoding');
        next();
    });

    // static cache headers
    app.use('/bower_components*', function(req, res, next){
        res.set('Cache-Control', 'public, max-age=2419200');
        next();
    });

    // set static directory
    app.use(express.static(process.cwd() + '/build'));

    // deeplink
    app.use('/dl/*', function(req, res, next){
        var path = req.baseUrl.replace('/dl/', '');
        var url = 'https://www.deeplink.me/tablelist.com/' + path;
        return res.redirect(url);
    });

    // file not found, route to index.html
    app.use(function(req, res, next){
        res.sendFile(process.cwd() + '/build/index.html');
    });

    // error handling
    app.use(function(err, req, res, next){
        res.status(404).send(err.message);
    });

    app.listen(port, function() {
        console.log('Listening on port: ' + port);
    });

    module.exports = app;

有没有人看到任何引人注目的东西?使用最新版本的Node 0.10.31和Express 4.8.6

更新:2014年8月29日

我对server.js文件进行了一些更改,删除了Express的sendFile和静态中间件。您可以在下面看到更新的图表,它看起来确实更好,但使用的内存比我个人喜欢的更多。更新的服务器也在下面。

Updated memory usage

    var newrelic = require('newrelic')
      , fs = require('fs')
      , express = require('express')
      , app = express()
      , ENV = process.env.NODE_ENV || 'development'
      , ENV_PROD = ENV == 'production'
      , SSL = ENV_PROD || process.env.SSL
      , port = process.env.PORT || 8080
      , config = require('../config')[ENV];

    console.log('ENV: ' + ENV);

    // force ssl
    app.use(function(req, res, next){
        if (SSL) {
            var protocol = req.get('x-forwarded-proto');
            if (protocol != 'https') {
                res.redirect(301, 'https://' + req.get('host') + req.url);
            } else {
                res.header('Strict-Transport-Security', 'max-age=31536000');
                next();
            }
        } else {
            next();
        }
    });

    // set default headers
    app.use(function(req, res, next){
        var cache = ENV == 'production' ? 3600 : 0;
        res.set('Cache-Control', 'public, max-age='+cache);
        res.set('Vary', 'Accept-Encoding');
        next();
    });

    // static cache headers
    app.use('/bower_components*', function(req, res, next){
        res.set('Cache-Control', 'public, max-age=2419200');
        next();
    });

    // add isFile to req
    app.use(function(req, res, next){
        var fileName = req.path.split('/').pop();
        var isFile = fileName.split('.').length > 1;
        req.isFile = isFile;
        next();
    });

    // static
    app.use(function(req, res, next){
        if (req.isFile) {
            var fileName = req.path.split('/').pop();
            var path = process.cwd() + '/build' + req.path;
            fs.readFile(path, function(err, data){
                if (!data) return next();
                res.contentType(fileName);
                res.send(data);
            });
        } else {
            next();
        }
    });

    // file not found, route to index.html
    app.use(function(req, res, next){
        if (req.isFile) {
            next(new Error('Not found'));
        } else {
            var path = process.cwd() + '/build/index.html';
            fs.readFile(path, function(err, data){
                if (err) return next(err);
                res.contentType('index.html');
                res.send(data);
            });
        }
    });

    // error handling
    app.use(function(err, req, res, next){
        res.status(404).send(err.message);
    });

    // start server
    app.listen(port, function() {
        console.log('Listening on port: ' + port);
    });

    module.exports = app;

1 个答案:

答案 0 :(得分:6)

这完全是因为模块' newrelic'。我们在Node上有各种不同的编写应用程序,它们都有问题。无论什么版本的“新浪潮”都是'你使用的,1.3.2 - 1.11.4,问题总是一样的,内存只会爆炸。

只需尝试评论require('newrelic')行,您就会发现内存消耗不断下降。