Утечка памяти в nodejs обещает дизайн? - PullRequest
0 голосов
/ 20 сентября 2018

Я заметил, что некоторые люди здесь рекомендуют использовать await / async и обещание вместо setTimeout напрямую, если вы хотите отложить выполнение чего-либо.Это код:

async wait (ms){
  return new Promise(resolve => setTimeout(resolve, ms));
}

Так что я бы использовал

await wait(3000);
my_function();

вместо

setTimeout(() => {
  my_function();
}, 3000);

Это имеет смысл, но я заметил, что если я это сделаю, яувеличение использования памяти, и в конечном итоге приложение вылетает с кучей нехватки памяти через несколько часов.

Это проблема в многообещающем дизайне nodejs или я что-то здесь упускаю?


Этот код воспроизводит проблему:

const heapdump = require('heapdump'),
      fs = require('fs');
class test {
  constructor(){
    this.repeatFunc();
  }
  async wait (ms){
    return new Promise(resolve => setTimeout(resolve, ms));
  }
  async repeatFunc(){ 
    // do some work...
    heapdump.writeSnapshot(__dirname + '/' + Date.now() + '.heapsnapshot');    

    await this.wait(5000); 
    await this.repeatFunc();
  }
}
new test();

Уведомление о дампе кучи продолжает увеличиваться каждые 5 секунд

При использовании setInterval этого не происходит:

const heapdump = require('heapdump'),
      fs = require('fs');
class test {
  constructor() {
    setInterval(this.repeatFunc, 5000);
  }
  repeatFunc() { 
    // do some work...
    heapdump.writeSnapshot(__dirname + '/' + Date.now() + '.heapsnapshot');    
  }
}
new test();

Ответы [ 2 ]

0 голосов
/ 20 сентября 2018

Чтобы избежать утечек памяти в обещании, рекомендуется очистить все таймауты после их использования.

function wait(delay) {
    return new Promise(function(resolve) {
        let id = setTimeout(function() { resolve(); clearTimeout(id);  }, delay);
    });
}

(async () => {
   await wait(2000);
   alert("Test");
})();
0 голосов
/ 20 сентября 2018

Вы написали бесконечно рекурсивную функцию, и каждый вызов функции возвращает новое обещание.Каждое обещание ожидает своего исполнения от внутреннего - так что да, оно, конечно, накапливает память.Если бы код был синхронным, вы бы получили исключение переполнения стека.

Просто используйте вместо этого цикл:

const heapdump = require('heapdump'),
      fs = require('fs');

async function wait(ms){
  return new Promise(resolve => setTimeout(resolve, ms));
}
async function repeat() {
  while (true) {
    // do some work...
    heapdump.writeSnapshot(__dirname + '/' + Date.now() + '.heapsnapshot');    

    await wait(5000); 
  }
}

repeat().then(() => console.log("all done"), console.error);

Я заметил, что некоторые люди здесь рекомендуютиспользуйте await / async и обещайте вместо setTimeout напрямую, если вы хотите отложить выполнение чего-либо.

Хорошо, это касается и меня, так как с обещаниями гораздо проще работать, особеннокогда вы хотите вернуть значение результата из асинхронной задачи или обработать ошибки.Но если вас не убеждает ни одно из преимуществ обещаний, ничто не заставит вас конвертировать уже работающий код в обещания.Просто продолжайте использовать стиль обратного вызова, пока не найдете подходящее применение для обещаний.

...