Обнаружена утечка памяти EventEmitter

Я получаю следующее предупреждение:

(node) warning: possible EventEmitter memory leak detected. 11 listeners added. Use emitter.setMaxListeners() to increase limit.
Trace: 
    at EventEmitter.<anonymous> (events.js:139:15)
    at EventEmitter.<anonymous> (node.js:385:29)
    at Server.<anonymous> (server.js:20:17)
    at Server.emit (events.js:70:17)
    at HTTPParser.onIncoming (http.js:1514:12)
    at HTTPParser.onHeadersComplete (http.js:102:31)
    at Socket.ondata (http.js:1410:22)
    at TCP.onread (net.js:354:27)

Я написал код, подобный этому в server.js:

http.createServer(
    function (req, res) { ... }).listen(3013);

Как это исправить?

Ответ 2

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

Я нашел эту страницу, потому что получил это предупреждение, и в моем случае была ошибка в некотором коде, который я использовал, который превращал глобальный объект в EventEmitter! Я бы посоветовал не увеличивать лимит во всем мире, потому что вы не хотите, чтобы эти вещи оставались незамеченными.

Ответ 3

По умолчанию максимум 10 слушателей могут быть зарегистрированы для любого отдельного события.

Если это ваш код, вы можете указать maxListeners через:

const emitter = new EventEmitter()
emitter.setMaxListeners(100)
// or 0 to turn off the limit
emitter.setMaxListeners(0)

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

require('events').EventEmitter.prototype._maxListeners = 100;

Конечно, вы можете отключить ограничения, но будьте осторожны:

// turn off limits by default (BE CAREFUL)
require('events').EventEmitter.prototype._maxListeners = 0;

КСТАТИ. Код должен быть в самом начале приложения.

ДОБАВИТЬ: начиная с узла 0.11, этот код также работает для изменения предела по умолчанию:

require('events').EventEmitter.defaultMaxListeners = 0

Ответ 4

Принятый ответ содержит семантику о том, как увеличить лимит, но, как указал @voltrevo, предупреждение есть по причине, и ваш код, вероятно, содержит ошибку.

Рассмотрим следующий ошибочный код:

//Assume Logger is a module that emits errors
var Logger = require('./Logger.js');

for (var i = 0; i < 11; i++) {
    //BUG: This will cause the warning
    //As the event listener is added in a loop
    Logger.on('error', function (err) {
        console.log('error writing log: ' + err)
    });

    Logger.writeLog('Hello');
}

Теперь рассмотрим правильный способ добавления слушателя:

//Good: event listener is not in a loop
Logger.on('error', function (err) {
    console.log('error writing log: ' + err)
});

for (var i = 0; i < 11; i++) {
    Logger.writeLog('Hello');
}

Ищите похожие проблемы в своем коде, прежде чем менять maxListeners (что объясняется в других ответах)

Ответ 5

Замените .on() на once(). Использование once() удаляет прослушиватели событий, когда событие обрабатывается той же функцией. Источник: http://nodeguide.com/beginner.html#using-eventemitters

Если это не помогло, переустановите restler с этим в вашем package.json "restler": "git://github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d"

Это связано с неправильной работой рестлера 0.10 с узлом. вы можете увидеть проблему закрытой на git здесь: https://github.com/danwrong/restler/issues/112 Однако npm еще не обновил это, поэтому вы должны обратиться к главе git.

Ответ 7

В моем случае это было child.stderr.pipe(process.stderr), которое вызывалось, когда я запускал 10 (или около того) экземпляров дочернего элемента. Итак, все, что приводит к присоединению обработчика события к одному объекту EventEmitter в LOOP, заставляет nodejs выбрасывать эту ошибку.

Ответ 8

Иногда эти предупреждения возникают, когда это не то, что мы сделали, а то, что мы забыли сделать!

Я столкнулся с этим предупреждением, когда установил пакет dotenv с номером npm, но был прерван до того, как я общался с добавлением инструкции require ('dotenv'). load() в начале моего приложения. Когда я вернулся в проект, я начал получать предупреждения об обнаружении утечки "Возможная ошибка EventEmitter".

Я предположил, что проблема была в том, что я сделал, а не в том, чего я не сделал!

Как только я обнаружил свой контроль и добавил оператор require, предупреждение об утечке памяти очистилось.

Ответ 9

У меня было это до сегодняшнего дня, когда я начал grunt watch. Наконец решено

watch: {
  options: {
    maxListeners: 99,
    livereload: true
  },
}

Раздражающее сообщение ушло.

Ответ 10

Я предпочитаю выслеживать и исправлять проблемы, а не подавлять журналы всякий раз, когда это возможно. После нескольких дней наблюдения за этой проблемой в моем приложении я понял, что настраиваю прослушиватели на req.socket в промежуточном программном обеспечении Express, чтобы перехватывать ошибки сокета io, которые продолжали появляться. В какой-то момент я узнал, что в этом нет необходимости, но я все равно держал слушателей. Я просто удалил их, и ошибка, с которой вы столкнулись, ушла. Я убедился, что это было причиной, запустив запросы к моему серверу со следующим промежуточным программным обеспечением и без него:

socketEventsHandler(req, res, next) {
        req.socket.on("error", function(err) {
            console.error('------REQ ERROR')
            console.error(err.stack)
        });
        res.socket.on("error", function(err) {
            console.error('------RES ERROR')
            console.error(err.stack)
        });
        next();
    }

Удаление этого промежуточного программного обеспечения остановило предупреждение, которое вы видите. Я бы посмотрел вокруг вашего кода и попытался найти то, где вы, возможно, настраиваете слушателей, которые вам не нужны.

Ответ 11

Вы сказали, что используете process.on('uncaughtException', callback);
Где вы выполняете это выражение? Является ли оно в пределах обратного вызова, переданного в http.createServer?
Если да, другая копия того же обратного вызова будет привязана к событию uncaughtException при каждом новом запросе, поскольку выполняется выполнение function (req, res) { ... } каждый раз, когда приходит новый запрос, и так будет оператор process.on('uncaughtException', callback);
Обратите внимание, что объект процесса является глобальным для всех ваших запросов и добавляет слушателей к его событию каждый раз, когда приходит новый запрос, не имеет никакого смысла. Возможно, вы не захотите такого поведения.
Если вы хотите добавить нового слушателя для каждого нового запроса, вы должны удалить все предыдущие прослушиватели, прикрепленные к событию, поскольку они больше не потребуются, используя:
process.removeAllListeners('uncaughtException');

Ответ 12

Наша команда исправила это: удаление пути реестра из нашего .npmrc. В файле rc у нас было два псевдонима пути, и один указывал на экземпляр Artifactory, который устарел.

Ошибка не имеет ничего общего с нашим фактическим кодом приложения, но все зависит от нашей среды разработки.

Ответ 13

У меня была такая же проблема. и проблема была вызвана, потому что я слушал порт 8080, на 2 слушателя.

setMaxListeners() работает нормально, но я бы не рекомендовал его.

правильный способ - проверить ваш код на наличие дополнительных прослушивателей, удалить прослушиватель или изменить номер порта, на котором вы слушаете, это решило мою проблему.

Ответ 14

Я обновил старую версию LTS, 6 что-то, до новой версии LTS 8.9.4, и мои ошибки исчезли.

Ответ 15

Вам необходимо очистить всех слушателей перед созданием новых, используя:

Клиент/Сервер

socket.removeAllListeners(); 

Предполагая, что сокет - это ваш клиентский сокет/или созданный сокет сервера.

Вы также можете подписаться на определенные прослушиватели событий, например, удалив прослушиватель connect следующим образом:

this.socket.removeAllListeners("connect");

Ответ 16

Версия узла: v11.10.1

Предупреждение от трассировки стека:

process.on('warning', e => console.warn(e.stack));
(node:17905) MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
MaxListenersExceededWarning: Possible EventEmitter memory leak detected. 11 wakeup listeners added. Use emitter.setMaxListeners() to increase limit
    at _addListener (events.js:255:17)
    at Connection.addListener (events.js:271:10)
    at Connection.Readable.on (_stream_readable.js:826:35)
    at Connection.once (events.js:300:8)
    at Connection._send (/var/www/html/fleet-node-api/node_modules/http2/lib/protocol/connection.js:355:10)
    at processImmediate (timers.js:637:19)
    at process.topLevelDomainCallback (domain.js:126:23)

После поиска проблем github, документирования и создания подобных утечек памяти генератора событий эта проблема наблюдалась из -за модуля node-apn, используемого для push-уведомлений iOS.

Это решило это:

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

Если вы постоянно создаете экземпляры Provider в своем приложении, обязательно вызовите Provider.shutdown(), когда вы закончите с каждым поставщиком, чтобы освободить его ресурсы и память.

Я создавал объект провайдера каждый раз, когда отправлялось уведомление, и ожидал, что gc его очистит.

Ответ 17

Поместите это в первую строку вашего server.js(или что-то еще, содержащее ваше главное приложение Node.js):

require('events').EventEmitter.prototype._maxListeners = 0;

и ошибка исчезнет:)