简体   繁体   中英

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:

It creates a net server, which closes the clients right after receiving any data, and binds it to the port 3000 in localhost . 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)

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.

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.

Initial heap snapshot

在此处输入图片说明

Final heap snapshot

在此处输入图片说明

As you can see in the final snapshot, bigBuffer is still held by the socket . I have no idea why the socket is still alive. All I can see in the retainers tree after socket is 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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