Socket.io 和 node.js,看不懂内存使用情况

lmq*_*kfh 5 memory-leaks node.js socket.io

我目前在我的服务器上使用 socket.io v1.4.2 和 node.js v0.10.29。我尝试跟踪我的应用程序中的内存泄漏,我不确定,但我认为 socket.io 是我问题的一部分。

所以这里是服务器的代码(演示示例):

var server = require ('http').createServer ();
var io = require ('socket.io')(server);

io.on ("connection", function (socket) {

    socket.on ('disconnect', function (data) { /* Do nothing */ });
});
Run Code Online (Sandbox Code Playgroud)

第 1 步:内存:58Mb

第 2 步:我创建了很多客户端(~10000),内存:300 Mb

第 3 步:我关闭所有客户端并等待 GC 完成他的工作

第 4 步:我查看我的内存:100 Mb :'(

第 5 步:与第 2 步和第 3 步相同

第 6 步:内存 160Mb...

依此类推,内存不断增长。

我认为 GC 是懒惰的,所以我使用以下代码重试:

setInterval (function () {
    global.gc ();
}, 30000);
Run Code Online (Sandbox Code Playgroud)

我用以下命令启动我的 app.js:

node --expose-gc app.js
Run Code Online (Sandbox Code Playgroud)

但我得到了同样的结果。

最后我尝试

var server = require ('http').createServer ();
var io = require ('socket.io')(server);

clients = {};
io.on ("connection", function (socket) {

    clients[socket.id] = socket;        
    socket.on ('disconnect', function (data) { 
        delete clients[socket.id];
    });

});
Run Code Online (Sandbox Code Playgroud)

我得到了同样的结果。我怎样才能释放这个内存?

编辑

我直接在我的主要来源上创建快照。

我使用以下命令安装新模块:

 npm install heapdump
Run Code Online (Sandbox Code Playgroud)

我在我的代码中这样写:

 heapdump = require ('heapdump');
 setInterval (function () { heapdump.writeSnapshot (); }, 30000);
Run Code Online (Sandbox Code Playgroud)

它每 30 秒对程序进行一次 heapdump,并将其保存在当前目录中。我使用 Chrome 的模块“配置文件”读取了堆转储。

所以,问题可能是 socket.io,因为我发现很多字符串没有被释放,我用 socket 发出。也许我没有以正确的方式编写发射?我这样做:

     var data1 = [1, 2, 3];
     var data2 = [4, 5, 6];
     var data3 = [7, 8, 9];
     socket.emit ('b', data1, data2, data3);
     data1 = [];
     data2 = [];
     data3 = [];
Run Code Online (Sandbox Code Playgroud)

在我的快照中说程序保留了以下字符串:“b [1, 2, 3] [4, 5, 6] [7, 8, 9]”在我的记忆中,数百万次我假设做 ?

我还进行了另一个(也许是愚蠢的?)测试:

    var t1 = new Date ();

    ...

    var t2 = new Date ();
    var data1 = [1, 2, 3];
    var data2 = [4, 5, 6];
    var data3 = [7, 8, 9];
    socket.emit ('b', data1, data2, data3);
    data1 = [];
    data2 = [];
    data3 = [];

    console.log ("LAG: " + t2 - t1);
    t1 = new Date ();
Run Code Online (Sandbox Code Playgroud)

我有这个结果:

    LAG: 1
    LAG: 1
    ...
    LAG: 13
    LAG: 2
    LAG: 26
    LAG: 3
    ...
    LAG: 100
    LAG: 10
    LAG: 1
    LAG: 1
    LAG: 120
    ...
    keeps growing
Run Code Online (Sandbox Code Playgroud)

编辑 2:

这是我的整个测试代码:

/* Make snapshot every 30s in current directory */
heapdump = require ('heapdump');
setInterval (function () { heapdump.writeSnapshot (); }, 30000);

/* Create server */
var server = require ('http').createServer ();
var io = require ('socket.io')(server);
var t1 = new Date ();

clients = {};
io.on ("connection", function (socket) {

    clients[socket.id] = socket;        
    socket.on ('disconnect', function (data) { 
        delete clients[socket.id];
    });
});

setInterval (function () { 

    var t2 = new Date ();
    for (c in clients) {
        var data1 = [1, 2, 3];
        var data2 = [4, 5, 6];
        var data3 = [7, 8, 9];
        clients[c].emit ('b', data1, data2, data3);
        data1 = [];
        data2 = [];
        data3 = [];
    }
    console.log ("LAG: " + t2 - t1);
    t1 = new Date (); 
}, 100);
Run Code Online (Sandbox Code Playgroud)

我不给客户代码。因为我认为:如果问题出在客户端,那么这是一个安全问题。事实上,这将是一种使服务器 RAM 饱和的简单方法。所以这是一种更好的 DDOS,我只是希望问题不在客户端。

jfr*_*d00 2

根据您包含的服务器代码进行编辑

在您的服务器上:

c.emit ('b', data1, data2, data3);` 
Run Code Online (Sandbox Code Playgroud)

应改为:

clients[c].emit('b', data1, data2, data3);
Run Code Online (Sandbox Code Playgroud)

c.emit()可能会抛出异常,因为c字符串socket.id和字符串没有.emit()方法。

原答案

您需要确定的是,内存的增长是否实际上是在 Node.js 堆中分配的内存,或者是否是尚未返回到操作系统并可供将来在 Node.js 中重用的空闲内存?测量 Node.js 进程使用的内存有助于了解它从系统中获取了什么,并且内存不应随着时间的推移而永远持续增加,但它并不能告诉您内部到底发生了什么。

仅供参考,只要您的 Node.js 应用程序有一些空闲周期,您就不必手动调用 GC。它会自己做这件事。

测量 Node.js 堆中正在使用的内容的常用方法是拍摄堆快照,运行步骤 1-4,拍摄堆快照,再次运行这些步骤,拍摄另一个堆快照,比较快照并查看结果Node.js 堆中的内存实际上在两种状态之间是不同的。

这将向您展示 Node.js 中实际使用的内容已发生变化。

这是一篇关于拍摄堆快照并在调试器中读取它们的文章:https://strongloop.com/strongblog/how-to-heap-snapshots/