【发布时间】:2014-10-01 04:30:18
【问题描述】:
我有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 的分析器中看到的。
初始堆快照
最终堆快照
正如您在最终快照中所见,bigBuffer 仍由socket 持有。我不知道为什么socket 还活着。在socket 之后,我在保留树中看到的只有owner in TCP @27447。您认为这可能是节点的错误吗?
我非常感谢任何帮助以了解正在发生的事情。
谢谢!
【问题讨论】:
-
难道底层操作系统还在完成网络(发送数据、等待来自服务器的 TCP ACK、关闭套接字等),因此与套接字相关的一切都是当您假设它是内部的 GC 时,它还没有完全可用。请记住,网络不是操作系统级别的同步任务。这需要时间。我建议您在再次致电
gc()几秒钟后拍摄您的最终快照。 -
@jfriend00 这就是为什么我在等待套接字的“结束”事件来触发 GC。
-
你确定“结束”事件意味着一切都在套接字上完成吗?另外,你在哪里关闭套接字?
-
@jfriend00 我在拍摄最后一张快照之前设置了一个较大的超时时间(10 秒),我仍然可以在堆中看到
socket。 -
在拍摄最后一个快照之前你在哪里关闭套接字?
标签: javascript node.js memory-leaks garbage-collection v8