简体   繁体   English

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

[英]Node.js net socket memory leak?

I have 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);

What test.js does is pretty straight forward: test.js的工作非常简单:

It creates a net server, which closes the clients right after receiving any data, and binds it to the port 3000 in localhost . 它创建一个网络服务器,该网络服务器在接收到任何数据后立即关闭客户端,并将其绑定到localhost中的端口3000 When the server listens, the onListen function is executed, which instantiates a socket that connects to the server, and then takes a heap snapshot (please notice that in the line 13 we set a 50MB bigBuffer to the socket, this is just to easily locate it in the heap snapshot) 服务器侦听时,将执行onListen函数,该函数实例化连接到服务器的socket ,然后进行堆快照(请注意,在第13行中,我们为套接字设置了50MB bigBuffer ,这只是为了轻松定位它在堆快照中)

Right after taking the initial snapshot, the sockets writes some data to the server and gets ended, this is when the writeEndSnapshot function gets executed, which waits for the next tick, forces a GC (garbage collection) cycle, and then takes a final heap snapshot. 在获取初始快照后, sockets将一些数据写入服务器并终止,这是当执行writeEndSnapshot函数时,它等待下一个刻度,强制执行GC(垃圾收集)周期,然后进行最后的堆快照。

It seemed pretty clear for me that by the time the final snapshot is taken, the socket should have been disposed, and therefore, garbage-collected. 对我来说,很清楚,在拍摄最终快照时,应该已经处置了套接字,因此已经进行了垃圾回收。 However, this is not what I'm seeing in the Google Chrome's profiler when I load the snapshots. 但是,加载快照时,这不是我在Google Chrome浏览器的分析器中看到的内容。

Initial heap snapshot 初始堆快照

在此处输入图片说明

Final heap snapshot 最终堆快照

在此处输入图片说明

As you can see in the final snapshot, bigBuffer is still held by the socket . 如您在最终快照中bigBufferbigBuffer仍然由socket持有。 I have no idea why the socket is still alive. 我不知道为什么socket还活着。 All I can see in the retainers tree after socket is owner in TCP @27447 . socket owner in TCP @27447后,我在保留树中看到的所有内容。 Do you think this might be a node's bug? 您是否认为这可能是节点的错误?

I'd really appreciate any help to understand what's going on. 我非常感谢您对了解正在发生的事情的任何帮助。

Thank you! 谢谢!

It turns out that if there's only one client socket, this wont get garbage collected. 事实证明,如果只有一个客户端套接字,则不会收集垃圾。 Here's an updated script now with two sockets: 这是现在带有两个套接字的更新脚本:

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);

Everything works fine now. 现在一切正常。 However, if you change the loop to instantiate just one socket, you'll see it keeps alive in the heap. 但是,如果将循环更改为仅实例化一个套接字,则会看到该循环在堆中保持活动状态。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM