简体   繁体   English

Memory 在承诺的情况下泄漏

[英]Memory leak in while with promises

I have anodejs cluster with a primary that handles worker cycles (in the while loop) and that listens to worker messages to progress in the cycle.我有一个nodejs 集群,它的主节点处理工作周期(在 while 循环中)并监听工作消息以在周期中进行。 (In my code index.js does not send messages on setInterval but on other type of event, I have here simplified the code to get the essence of the problem) (在我的代码中 index.js 不会在 setInterval 上发送消息,而是在其他类型的事件上发送消息,我在这里简化了代码以了解问题的本质)

Server.js服务器.js

var cluster = require('cluster');
const ClusterMessages = require('cluster-messages');
const messages = new ClusterMessages();

if (cluster.isMaster){
    let worker = cluster.fork()
    console.log(cluster);
    
    (async ()=>{
    let cycle = 0
    while(true){
        console.log(cycle);
        cycle ++
        await Promise.all([
            enough(),
        ])
    }
    function enough () {
        return new Promise(resolve => {
            messages.on('enough', () => {
                console.log('enough');
                resolve()
            });
        });
    }})()
} else {
    require('./index.js')
}

Index.js索引.js

const ClusterMessages = require('cluster-messages');
const messages = new ClusterMessages();

setInterval(() => {
    messages.send('enough');
}, 1000);

The code is working fine (as such, in this example and in my code) but there seems to be a memory leak as you can understand from the output of this code:该代码工作正常(因此,在本示例和我的代码中),但似乎存在 memory 泄漏,正如您可以从该代码的 output 中理解的那样:

0
enough
1
enough
enough
2
enough
enough
enough
3
enough
enough
enough
enough...

I tried several things like exchanging new Promise and messages.on(), add a return in the callback of the promise but I have no clue what is happening here.我尝试了几件事,比如交换新的 Promise 和 messages.on(),在 promise 的回调中添加返回,但我不知道这里发生了什么。 Any ideas?有任何想法吗?

Every call of enough() installs another listener for the enough event on messages .每次调用enough()都会为messages上的enough事件安装另一个侦听器。 They never get removed, leaking memory (and leading to an increasing number of logs per event).它们永远不会被删除,泄漏 memory(并导致每个事件的日志数量增加)。 Instead, use the once method to install the listener:相反,使用once方法安装监听器:

function enough () {
    return new Promise(resolve => {
        messages.once('enough', () => {
//               ^^^^
            console.log('enough');
            resolve();
        });
    });
}

Or even simpler, using once :甚至更简单,使用once

const { once } = require('events');
function enough() {
    return once(messages, 'enough');
}

In your particular example, I would recommend not to use promises to handle the events.在您的特定示例中,我建议不要使用承诺来处理事件。 You might even miss events that are fired while you are removing and re-attaching a listener.您甚至可能会错过在删除和重新附加侦听器时触发的事件。 Just write写吧

let cycle = 0
messages.on('enough', () => {
    console.log(cycle);
    cycle++;
});

If for some reason you need a loop that you can break from or await other things in, I would recommend an asynchronous iterator, built with on :如果由于某种原因您需要一个可以中断或await其他事情的循环,我会推荐一个异步迭代器,使用on构建:

const { once } = require('events');
(async () => {
    let cycle = 0
    for await (const _ of on(messages, 'enough')) {
        console.log(cycle);
        cycle++;
    }
})();

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

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