每次请求导致Nodejs内存直线上升的问题
每次请求导致Nodejs内存直线上升的问题
最近使用的ghost框架开发一个科技博客项目。项目运行几天后,发现内存占用达到了5G多。 ** 用户量上升,系统只能奔溃了 ** 花了点时间追查内存问题。
发现每次请求,内存在增加
用express 重现问题
- 用express 搭建一个最简单的web项目,
- 用 pm2 启动和查看内存状况
pm2 monit
- 用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 么
线上的项目是怎么管理内存的
每次请求导致Node.js内存直线上升的问题
最近我在使用Ghost框架开发一个科技博客项目时遇到了一个棘手的问题。项目运行几天后,我发现内存占用达到了5GB以上。随着用户量的增加,系统最终会崩溃。
发现每次请求,内存在增加
为了追踪问题,我使用Express重新构建了一个简单的Web项目,并用PM2来启动和监控内存状况:
- 使用Express搭建一个最简单的Web项目。
- 使用PM2启动并查看内存状态:
pm2 monit
- 使用
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中,垃圾回收机制通常会自动处理内存清理,但有时由于某些对象被意外地保留在内存中,会导致内存泄漏。在这种情况下,可以尝试以下方法来解决:
- 检查内存泄漏源:使用工具如
memwatch-next
或heapdump
来帮助查找内存泄漏的具体原因。 - 优化代码:确保所有事件监听器在不再需要时被正确解除绑定。
- 避免全局变量:全局变量可能导致对象长时间不被垃圾回收。
- 手动触发垃圾回收:虽然不推荐频繁使用,但在调试时可以考虑手动触发垃圾回收:
global.gc(); // 需要在启动Node.js时加上--expose-gc参数
线上项目的内存管理
对于生产环境中的Node.js应用,建议采取以下措施来管理内存:
- 定期重启服务:通过定时任务定期重启服务,以释放累积的内存。
- 使用内存分析工具:如
New Relic
或AppDynamics
等工具可以帮助监控和分析内存使用情况。 - 优化代码逻辑:确保代码逻辑没有不必要的内存保留,例如缓存数据的管理。
希望这些解决方案能帮助你解决内存直线上升的问题。
- 你的服务器是不是对每个请求用新建Buffer来打开和输出style.css
- 静态文件应该加入缓存策略
我也遇到这个问题 专门新建一个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');
});
解释
-
使用
request-promise-native
:- 我们使用
request-promise-native
替代原始的request
库,因为它返回一个 Promise,更容易处理异步操作。
- 我们使用
-
响应处理:
- 当请求成功时,我们发送请求得到的内容并确保响应结束 (
res.end()
或res.send()
)。 - 如果请求失败,我们返回一个错误状态码(例如 500)。
- 当请求成功时,我们发送请求得到的内容并确保响应结束 (
-
避免重复请求:
- 原始代码中使用
setTimeout(req(), 500)
来重复调用请求函数,这样会导致内存不断增加。改为在每次请求成功或失败后重新发起新的请求可以避免内存泄漏。
- 原始代码中使用
总结
通过以上改进,可以有效避免每次请求导致内存持续增加的问题。关键是确保每次请求完成后正确地结束响应,并避免重复无限制地发起请求。如果还有内存问题,建议使用 Node.js 的内存分析工具(如 heapdump
)进一步分析内存使用情况。