Node.js网络套接字内存泄漏?

时间:2014-10-01 04:30:18

标签: javascript node.js memory-leaks garbage-collection v8

我有this script

var net = require("net")
,   heapdump = require("heapdump");

function onConnection (client) {
  client.on("data", function (data) {
    client.end();
  });
};

function onListen () {
  var socket = net.connect({host: "127.0.0.1", port: 3000});

  socket.bigBuffer = new Buffer(50000000); //50MB Buffer

  heapdump.writeSnapshot(__dirname + "/initial.heapsnapshot", function writeInitialSnapshot () {
    console.log("Wrote initial heap snapshot");
    socket.write("data");
  });

  socket.on("close", function () {
    writeEndSnapshot();
  });
};

function writeEndSnapshot () {
  setTimeout(function () {
    console.log("Running GC");
    gc();

    heapdump.writeSnapshot(__dirname + "/final.heapsnapshot", function writeFinalSnapshot () {
      console.log("Wrote final heap snapshot");
    });
  }, 1000);
};

net.createServer(onConnection).listen(3000, onListen);

test.js 的作用非常简单:

它会创建一个 net 服务器,它会在收到任何数据后立即关闭客户端,并将其绑定到 localhost 中的端口 3000 。当服务器侦听时,执行onListen函数,该函数实例化连接到服务器的socket,然后获取堆快照(请注意行 13 我们为套接字设置了50MB bigBuffer,这只是为了在堆快照中轻松找到它)

在获取初始快照之后,sockets将一些数据写入服务器并结束,这是writeEndSnapshot函数执行时等待下一个滴答,强制GC(垃圾收集)循环,然后获取最终的堆快照。

对我来说,似乎很清楚,在拍摄最终快照时,套接字应该已经处理好,因此会被垃圾收集。但是,当我加载快照时,这不是我在Google Chrome的分析器中看到的。

初始堆快照

enter image description here

最终堆快照

enter image description here

正如您在最终快照中看到的那样,bigBuffer仍然保留socket。我不知道为什么socket还活着。 socket owner in TCP @27447之后我在保留树中看到的所有内容。你认为这可能是节点的错误吗?

我非常感谢能帮助您了解正在发生的事情。

谢谢!

1 个答案:

答案 0 :(得分:0)

事实证明,如果只有一个客户端套接字,则不会收集垃圾。这是一个带有两个套接字的更新脚本:

var net = require("net")
,   heapdump = require("heapdump");

function onConnection (client) {
  client.on("data", function (data) {
    client.end();
  });
};

function onListen () {
  var socket
  ,   sockets = []
  ,   closedSockets = 0;

  for (var i = 0; i < 2; i++) {
    socket = net.connect({host: "127.0.0.1", port: 3000});
    sockets.push(socket);
    socket.bigBuffer = new Buffer(25000000); //25MB Buffer

    socket.on("close", function () {
      if (++closedSockets == sockets.length) {
        writeEndSnapshot();
      };
    });
  };

  heapdump.writeSnapshot(__dirname + "/initial.heapsnapshot", function () {
    console.log("Wrote initial heap snapshot");
    for (var i = 0; i < sockets.length; i++) {
      sockets[i].write("data");
    };
  });
};

function writeEndSnapshot () {
  setTimeout(function () {
    console.log("Running GC");
    gc();

    heapdump.writeSnapshot(__dirname + "/final.heapsnapshot", function () {
      console.log("Wrote final heap snapshot");
    });
  }, 1000);
};

net.createServer(onConnection).listen(3000, onListen);

现在一切正常。但是,如果您更改循环以仅实例化一个套接字,那么您将看到它在堆中保持活动状态。