Nodejs 内存泄露 很诡异的问题 倒是libstdc++ delete[] 有问题
Nodejs 内存泄露 很诡异的问题 倒是libstdc++ delete[] 有问题
server.js
var net=require(“net”)
var server = net.createServer(function (socket) { socket.on(“error”,function(e){ console.log(e) }) });
server.listen(7888,function() { address = server.address(); console.log(“opened server on %j”, address); });
client.js
var net=require(“net”) max=100000 count=0 client=net.createConnection(7888,function(){ console.log(“con”) buf = new Buffer(16*1024).toString() for(i=0;i<max;i++){ b = client.write(buf,function(){ count++; if(count==max){ console.log(“end”) client.end() } }) } })
setTimeout(function(){ console.log(1) },100000)
当 我看到end 时内存 top -p pid ,发现内存rss 1.3g 一直不下去了。
但是当我把 buf = new Buffer(161024).toString() 变成 buf = new Buffer(161024) 时内存就很小
大侠能给解释一下么
值得怀疑的地方 src/stream_wap.cc:346
char * storage = new char[sizeof(WriteWrap)+storgize+15] this is temporary
in src/stream_wap.cc:463
MakeCallback(); --> client.write(buf,function(){ count++; if(count==max){ console.log(“end”) client.end() } }) req_wrap->~WriteWrap(); delete[] reinterpret_cast(req_wrap)
这个帖子讨论了一个关于 Node.js 内存泄漏的诡异问题,涉及到 libstdc++
的 delete[]
操作。我们可以通过分析代码来理解这个问题。
代码分析
服务器端代码 (server.js
)
var net = require("net");
var server = net.createServer(function (socket) {
socket.on("error", function(e) {
console.log(e);
});
});
server.listen(7888, function() {
var address = server.address();
console.log("opened server on %j", address);
});
服务器端代码创建了一个监听在 7888
端口的 TCP 服务器,并处理连接错误。
客户端代码 (client.js
)
var net = require("net");
var max = 100000;
var count = 0;
var client = net.createConnection(7888, function() {
console.log("con");
var buf = new Buffer(16 * 1024).toString(); // 问题出在这里
for (var i = 0; i < max; i++) {
var b = client.write(buf, function() {
count++;
if (count == max) {
console.log("end");
client.end();
}
});
}
});
setTimeout(function() {
console.log(1);
}, 100000);
客户端代码连接到服务器并发送大量数据。关键在于 var buf = new Buffer(16 * 1024).toString();
这一行。通过 .toString()
方法将 Buffer
转换为字符串,这会导致创建大量的临时字符串对象。
问题分析
-
临时字符串对象:
- 当使用
new Buffer(16 * 1024).toString()
创建一个临时字符串时,Node.js 需要分配内存来存储这些字符串。 - 如果这些字符串没有被正确地垃圾回收(GC),则会导致内存泄漏。
- 当使用
-
内存泄漏:
- 在
client.write()
中,每次写入操作都会创建一个新的临时字符串对象。 - 如果这些字符串对象没有被及时释放,就会导致内存占用不断增加,从而引发内存泄漏。
- 在
-
libstdc++
的delete[]
问题:- 问题可能与 C++ 库中的
delete[]
操作有关,特别是在处理大量临时字符串对象时。 - 当 Node.js 试图释放这些临时字符串对象时,可能会触发 C++ 库中的
delete[]
操作,如果操作不当,可能会导致内存泄漏。
- 问题可能与 C++ 库中的
解决方案
为了避免内存泄漏,可以尝试以下几种方法:
-
避免创建临时字符串对象:
- 直接使用
Buffer
对象进行数据传输,而不是将其转换为字符串。 - 修改客户端代码中的
buf
创建方式:var buf = new Buffer(16 * 1024); // 不使用 toString()
- 直接使用
-
优化内存管理:
- 确保所有临时对象都能被正确地垃圾回收。
- 使用
process.memoryUsage()
监控内存使用情况。
通过上述修改,可以减少内存泄漏的风险,并提高程序的稳定性。
https://github.com/joyent/node/issues/4524 这个是我在github上的提问。 感觉没有给真正的解决
var net=require(“net”) max=100000 count=0 buf = new Buffer(16*1024).toString() client=net.createConnection(7888,function(){ write() })
function write(){ client.write(buf,function(){ count++ if(count==max){ console.log(“e”) return; } write() })
}
setTimeout(function(){ console.log(1) },1000000000)
这么做就是正确的,不知道为什么那里占用内存了
从你提供的代码来看,问题出在 buf.toString()
上。当你调用 new Buffer(16 * 1024).toString()
时,生成了一个临时字符串对象。由于 Node.js 的垃圾回收机制,这些临时字符串对象可能没有被及时释放,从而导致内存泄漏。
示例代码解释
首先,我们来看一下修改前后的代码对比:
修改前的代码
buf = new Buffer(16 * 1024).toString()
这里,new Buffer(16 * 1024)
创建了一个新的 Buffer 对象,然后 toString()
方法将其转换为一个字符串。然而,toString()
生成的字符串对象并没有立即被释放,可能会导致内存占用增加。
修改后的代码
buf = new Buffer(16 * 1024)
这样,只创建了一个 Buffer 对象,并没有生成额外的字符串对象,因此不会导致内存泄漏。
代码示例
下面是修改后的完整代码:
// server.js
var net = require("net");
var server = net.createServer(function (socket) {
socket.on("error", function (e) {
console.log(e);
});
});
server.listen(7888, function () {
address = server.address();
console.log("opened server on %j", address);
});
// client.js
var net = require("net");
const max = 100000;
let count = 0;
const client = net.createConnection(7888, function () {
console.log("con");
const buf = new Buffer(16 * 1024);
for (let i = 0; i < max; i++) {
client.write(buf, function () {
count++;
if (count === max) {
console.log("end");
client.end();
}
});
}
});
setTimeout(function () {
console.log(1);
}, 100000);
总结
通过避免使用 .toString()
方法,直接使用 Buffer 对象可以减少内存泄漏的可能性。因为 .toString()
方法会生成一个新的字符串对象,而这个对象如果没有被及时释放,就会导致内存占用增加。