Socket.io和node.js无法理解内存使用情况

时间:2016-05-30 01:24:49

标签: node.js memory-leaks 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 */ });
});

第1步:记忆:58Mb

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

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

第4步:我看看我的记忆:100 Mb:'(

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

第6步:记忆160Mb ......

等等,内存不断增长。

我认为GC很懒,所以我重试以下代码:

setInterval (function () {
    global.gc ();
}, 30000);

我用以下内容启动app.js:

node --expose-gc app.js

但我有同样的结果。

最后我试试

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

});

我得到了同样的结果。 我怎样才能释放这段记忆?

修改

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

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

 npm install heapdump

我在我的代码中写道:

 heapdump = require ('heapdump');
 setInterval (function () { heapdump.writeSnapshot (); }, 30000);

程序每30秒执行一次dumpdump,并将其保存在当前目录中。 我用Chrome的模块'profiles'读取了heapdump。

所以,问题可能是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 = [];

在我的快照中说该程序保留以下字符串:“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 ();

我有这个结果:

    LAG: 1
    LAG: 1
    ...
    LAG: 13
    LAG: 2
    LAG: 26
    LAG: 3
    ...
    LAG: 100
    LAG: 10
    LAG: 1
    LAG: 1
    LAG: 120
    ...
    keeps growing

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

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

1 个答案:

答案 0 :(得分:1)

根据您收录的服务器代码进行修改

在您的服务器上:

c.emit ('b', data1, data2, data3);` 

应更改为:

clients[c].emit('b', data1, data2, data3);

c.emit()可能会抛出异常,因为csocket.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/