为什么我的interval函数在Node.js中导致内存泄漏?

时间:2017-10-20 06:03:42

标签: node.js memory-leaks

我有一个遇到内存泄漏的Node.js服务器。它使用socket.io向连接的客户端发送消息。我已经设置了一个每分钟向客户端发送一次消息的函数。功能是:

var message = "smile";
const doEveryMinute = (socket) => {
    setTimeout(() => {
        setInterval(() => doEveryMinute(socket), 6000);
        socket.emit('smile', message);   
    }, (60 - date.getSeconds()) * 1000);
}

当用户通过io.on函数连接时调用该函数:

io.on('connection', function (socket){
    doEveryMinute(socket);
});

我不明白为什么这会导致内存泄漏,但肯定会导致内存泄漏。我可以在htop看到ram缓慢但肯定会填满,直到服务器崩溃显示memory overflow exception消息。

问题:

为什么此代码会导致内存泄漏?

1 个答案:

答案 0 :(得分:1)

首先,6000是6秒,而不是60秒。

您永远不会致电clearInterval,因此您使用setInterval创建的计时器将永远停留,每6秒调用一次。请记住,这是setInterval,而不是setTimeout,因此定时器在第一次触发后不会停止。

本身并不一定是个问题,因为单个计时器的内存使用量可以忽略不计。

但是,计时器调用的函数调用doEveryMinute,这将创建另一个计时器。随着每个计时器在6秒后创建另一个计时器,它将呈指数级增长。

如果您只想每60秒发送一条消息,则不需要递归,只需一个调用emit的计时器:

var message = "smile";
const doEveryMinute = (socket) => {
    setTimeout(() => {
        setInterval(() => socket.emit('smile', message), 60000);
    }, (60 - date.getSeconds()) * 1000);
}

请注意,这仍然不是完美的,因为它永远不会停止计时器,您需要在连接断开时向clearInterval添加合适的呼叫。我对于setInterval在60年代后开火的可靠性做出了一些可疑的假设。我想知道你的原始代码是否试图处理定时器的不精确性?这没关系,但如果你想这样做,你需要坚持setTimeout而不是setInterval