每次请求导致Nodejs内存直线上升的问题

每次请求导致Nodejs内存直线上升的问题

最近使用的ghost框架开发一个科技博客项目。项目运行几天后,发现内存占用达到了5G多。 ** 用户量上升,系统只能奔溃了 ** 花了点时间追查内存问题。

发现每次请求,内存在增加

用express 重现问题

  1. 用express 搭建一个最简单的web项目,
  2. 用 pm2 启动和查看内存状况
pm2 monit
  1. 用request库,不断请求静态资源文件 style.css,或者直接请求 主页 http://127.0.0.1:3001/
var request = require('request');
var count = 0;
function req(){
    count ++;
    request('http://127.0.0.1:3001/stylesheets/style.css', function (error, response, body) {
        if (!error && response.statusCode === 200) {
            //console.log(body) // Print the google web page.
            console.log(count);
            setTimeout(req(),500);
        }
    });
}
req();

内存直线上升,关闭req请求后,内存也不释放,难道一定要手动global.gc 么

线上的项目是怎么管理内存的


9 回复

每次请求导致Node.js内存直线上升的问题

最近我在使用Ghost框架开发一个科技博客项目时遇到了一个棘手的问题。项目运行几天后,我发现内存占用达到了5GB以上。随着用户量的增加,系统最终会崩溃。

发现每次请求,内存在增加

为了追踪问题,我使用Express重新构建了一个简单的Web项目,并用PM2来启动和监控内存状况:

  1. 使用Express搭建一个最简单的Web项目。
  2. 使用PM2启动并查看内存状态:
    pm2 monit
    
  3. 使用request库不断请求静态资源文件style.css,或者直接请求主页(http://127.0.0.1:3001/):
    var request = require('request');
    var count = 0;
    
    function req() {
        count++;
        request('http://127.0.0.1:3001/stylesheets/style.css', function (error, response, body) {
            if (!error && response.statusCode === 200) {
                console.log(count);
                setTimeout(req, 500); // 注意这里setTimeout的写法,应该传入函数引用而不是调用结果
            }
        });
    }
    
    req();
    

从上述代码中可以看到,每次请求都会增加一个计数器count,并在控制台输出当前请求次数。通过这种方式,我们可以看到内存直线上升。即使停止请求后,内存也没有释放,这表明可能存在内存泄漏问题。

解决方案

在Node.js中,垃圾回收机制通常会自动处理内存清理,但有时由于某些对象被意外地保留在内存中,会导致内存泄漏。在这种情况下,可以尝试以下方法来解决:

  1. 检查内存泄漏源:使用工具如memwatch-nextheapdump来帮助查找内存泄漏的具体原因。
  2. 优化代码:确保所有事件监听器在不再需要时被正确解除绑定。
  3. 避免全局变量:全局变量可能导致对象长时间不被垃圾回收。
  4. 手动触发垃圾回收:虽然不推荐频繁使用,但在调试时可以考虑手动触发垃圾回收:
    global.gc(); // 需要在启动Node.js时加上--expose-gc参数
    

线上项目的内存管理

对于生产环境中的Node.js应用,建议采取以下措施来管理内存:

  1. 定期重启服务:通过定时任务定期重启服务,以释放累积的内存。
  2. 使用内存分析工具:如New RelicAppDynamics等工具可以帮助监控和分析内存使用情况。
  3. 优化代码逻辑:确保代码逻辑没有不必要的内存保留,例如缓存数据的管理。

希望这些解决方案能帮助你解决内存直线上升的问题。


  1. 你的服务器是不是对每个请求用新建Buffer来打开和输出style.css
  2. 静态文件应该加入缓存策略

我也遇到这个问题 专门新建一个express 的空白项目,每次访问都会增加一点内存 用的是node 0.10.29版本 不知道是不是版本的问题

首先这样的静态文件不应该直接走express server,用nginx什么的最好,其次为什么不用stream。。。

。。。。 我是用的nginx做的代理,静态文件直接访问了,然后动态的转发到nodejs的端口,http://blog.gaoqixhb.com

我用的阿里云的centos,才1G内存,完全没事额…

服务器操作系统、Node.js和Express的版本是什么?

能不能写个重现问题的最小用例,托管在github.com上?这样,大家就可以clone下来,仔细研究下。

用以下代码请一个 24kb 的 style.css 文件12W次,内存稳定在112MB。 虽然内存会上升,但是会稳定在一个值。nodejs 还是不错的

var request = require('request');
var async = require('async');
var count = 0;
async.forever(
    function(next) {
        request('http://localhost:3001/stylesheets/style.css', function (error, response, body) {
            if (!error && response.statusCode === 200) {
                console.log(count++);
            }
            next();
        });
    },
    function(err) {

    }

);

setTimeout(req(),500);

应该是你这句的问题吧。req()执行之后并无返回,于是创建定时器。然后继续执行请求。继续创建定时器。

你一个请求完成的时间应该在500ms以内。然后定时器不停创建。

改为

setTimeout(req, 500);

就解决了。

从你提供的信息来看,内存泄漏可能是由于请求未正确结束导致的。下面是一个简单的示例代码来说明如何解决这个问题,并附上解释。

示例代码

var express = require('express');
var app = express();
var request = require('request-promise-native'); // 使用 promise 版本的 request

app.get('/style.css', function (req, res) {
    request('http://127.0.0.1:3001/stylesheets/style.css')
        .then(function (body) {
            res.send(body); // 将请求到的内容发送给客户端
            req.res.end(); // 确保响应结束
        })
        .catch(function (err) {
            res.status(500).send('Error fetching resource');
        });
});

app.listen(3001, function () {
    console.log('Server running on port 3001');
});

解释

  1. 使用 request-promise-native:

    • 我们使用 request-promise-native 替代原始的 request 库,因为它返回一个 Promise,更容易处理异步操作。
  2. 响应处理:

    • 当请求成功时,我们发送请求得到的内容并确保响应结束 (res.end()res.send())。
    • 如果请求失败,我们返回一个错误状态码(例如 500)。
  3. 避免重复请求:

    • 原始代码中使用 setTimeout(req(), 500) 来重复调用请求函数,这样会导致内存不断增加。改为在每次请求成功或失败后重新发起新的请求可以避免内存泄漏。

总结

通过以上改进,可以有效避免每次请求导致内存持续增加的问题。关键是确保每次请求完成后正确地结束响应,并避免重复无限制地发起请求。如果还有内存问题,建议使用 Node.js 的内存分析工具(如 heapdump)进一步分析内存使用情况。

回到顶部