node.js Утечка памяти при чтении файла

#javascript #node.js #file-io #memory-leaks

#javascript #node.js #file-io #утечки памяти

Вопрос:

Я использую node.js считывать изображение каждую секунду. Идея состоит в том, чтобы позже перенести его в веб-браузеры, превратив в простой поток. Код выглядит следующим образом:

 var fs      = require("fs");
var intervalTimerObj;

function startStream() {
    if(!intervalTimerObj) {
        intervalTimerObj = setInterval( updateStream  , 1000);
    }
}

function updateStream(){
    fs.readFile( __dirname   "/pic.jpg", function(err, image) {

    });
}

startStream();
 

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

Что я делаю не так? Есть ли какой-нибудь способ «освободить» переменную изображения? Я пытался свести его к нулю.

Комментарии:

1. Не используйте setInterval функцию обновить поток, когда вы закончили чтение изображения при fs.readFile обратном вызове. лучше прочитать изображение, а затем, если вам действительно нужен этот интервал в 1000 мс, использовать setTimeout его для начала следующего чтения

2. Просто попытался вместо этого использовать setTimeout. Все еще продолжает красть всю мою память.

3. В любом случае, почему ты делаешь это каждые 1000 мс?

4. Идея состоит в том, чтобы каждую секунду делать снимок, а затем передавать его в веб-браузеры с помощью socket.io

Ответ №1:

Это лучший подход. setInterval() здесь не следует использовать, поскольку это может привести к одновременному выполнению одной и той же задачи. Используйте setTimeout() вместо этого. Идеальное место для этого readFile() — обратный вызов inside:

 var fs            = require("fs");
var timeoutHandle = null;

function startTimeout() {
  stopTimeout();
  timeoutHandle = setTimeout(updateStream, 1000);
}

function stopTimeout() {
  clearTimeout(timeoutHandle);
}

function updateStream(){
    fs.readFile( __dirname   "/pic.jpg", function(err, image) {
      // ...

      startTimeout(); // Make sure this line is always executed
    });
}

startTimeout();
 

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

Комментарии:

1. Я запускаю вашу функцию startTimeout, но все равно память никогда не освобождается. Каждый раз, когда загружается изображение, моя память увеличивается. Работает ли startTimeout для вас?

2. Я долго тестировал ваше решение, и, похоже, использование памяти стабилизируется при использовании памяти ~ 40% (200 МБ). Этого следовало ожидать? Кстати, спасибо за код!

3. Да, это кажется нормальным. Вы должны быть очень осторожны при работе с большими объемами данных внутри циклов. Рад помочь!

Ответ №2:

Попробуйте это

 function startStream() {
    if(!intervalTimerObj) {
        intervalTimerObj = setTimeout( updateStream  , 1000);
    }
}

function updateStream(){
    fs.readFile( __dirname   "/pic.jpg", function(err, image) {
       //OK file is read
       //do yoyr stuff with it....
       // Now start next read
       startStream()
    });
}

startStream();
 

Комментарии:

1. Спасибо за код. Тем не менее, моя память постоянно увеличивается. Я отслеживаю оперативную память с помощью команды top (используя Linux), и она никогда не отключается.

2. Я предполагаю, что вы где-то входите в цикл вызовов circle. Проверьте свой код, отладьте, если возможно, и придумайте лучший шаблон. Если новая проблема вернется, отправьте вопрос. Этот код является таким шаблоном. 2 функции вызывают друг друга