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)


4 回复

这个帖子讨论了一个关于 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 转换为字符串,这会导致创建大量的临时字符串对象。

问题分析

  1. 临时字符串对象:

    • 当使用 new Buffer(16 * 1024).toString() 创建一个临时字符串时,Node.js 需要分配内存来存储这些字符串。
    • 如果这些字符串没有被正确地垃圾回收(GC),则会导致内存泄漏。
  2. 内存泄漏:

    • client.write() 中,每次写入操作都会创建一个新的临时字符串对象。
    • 如果这些字符串对象没有被及时释放,就会导致内存占用不断增加,从而引发内存泄漏。
  3. libstdc++delete[] 问题:

    • 问题可能与 C++ 库中的 delete[] 操作有关,特别是在处理大量临时字符串对象时。
    • 当 Node.js 试图释放这些临时字符串对象时,可能会触发 C++ 库中的 delete[] 操作,如果操作不当,可能会导致内存泄漏。

解决方案

为了避免内存泄漏,可以尝试以下几种方法:

  1. 避免创建临时字符串对象:

    • 直接使用 Buffer 对象进行数据传输,而不是将其转换为字符串。
    • 修改客户端代码中的 buf 创建方式:
      var buf = new Buffer(16 * 1024); // 不使用 toString()
      
  2. 优化内存管理:

    • 确保所有临时对象都能被正确地垃圾回收。
    • 使用 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() 方法会生成一个新的字符串对象,而这个对象如果没有被及时释放,就会导致内存占用增加。

回到顶部