olası EventEmitter bellek sızıntısı algılandı


231

Aşağıdaki uyarıyı alıyorum:

(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'de böyle bir kod yazdım:

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

Bunu nasıl düzeltirim?


46
process.on('warning', e => console.warn(e.stack));Uyarıda hata ayıklamak için kullanın . process.setMaxListeners(0);Uyarı bir nedenden dolayı orada olduğu için kullanmayın .
Shwetabh Shekhar

Teşekkür ederim. çok kullanışlı talimat.
Abdullah Al Farooq

bu hata bana geliyor yarn install. yığın iz eklemek için bu satırı nereye koyabilirim?
Sonic Soul

Yanıtlar:


94

Bu, düğüm olayında açıklanmaktadır.

Bu Düğümün hangi sürümü? Başka hangi kodun var? Bu normal bir davranış değil.

Kısacası: process.setMaxListeners(0);

Ayrıca bkz: node.js - istek - “emitter.setMaxListeners ()” nasıl yapılır?


1
v0.6.11 ... Her şeyi yaptım ama uyarı hala orada. :(
Riz

5
Ben kullanıyorumprocess.on('uncaughtException', callback);
Riz

9
process.setMaxListeners(0); // OMG, its so simple... :D
Riz

11
Maksimum dinleyici sınırını kaldırmam. Uyarı almazsınız, ancak bellek sızıntısı alırsınız.

15
Bu cevap tüm bu oyları nasıl aldı ve doğru cevap olarak seçildi? çalışmasına rağmen, ama bu tamamen yanlış !!
ProllyGeek

204

Burada uyarının bir nedenden ötürü olduğunu ve doğru düzeltmenin limiti arttırmak değil , aynı etkinliğe neden bu kadar çok dinleyici eklediğinizi bulmak için iyi bir şans olduğunu belirtmek isterim. Sınırı sadece bu kadar çok dinleyicinin neden eklendiğini biliyorsanız ve bunun gerçekten istediğiniz şey olduğundan eminseniz sınırını artırın.

Bu uyarıyı aldım çünkü bu sayfayı buldum ve benim durumumda kullandığım bazı kodda global nesneyi bir EventEmitter'a dönüştüren bir hata vardı! Kesinlikle küresel olarak limiti artırmaya karşı tavsiye ediyorum çünkü bu şeylerin fark edilmesini istemiyorsunuz.


14
+1. Kabul. Uyarı, potansiyel sızıntı durumunu gösterir ve maxListener'ların dikkatsizce artırılması sorunu çözmeyecektir. jongleberry.com/understanding-possible-eventemitter-leaks.html
Jeremiah Adams

3
"Uyarı: Olası EventEmitter bellek sızıntısı algılandı. 11 hata dinleyicisi eklendi. Sınırı artırmak için emitter.setMaxListeners () kullanın". Ne aramalıyız?
Phil

2
Ancak bu hata iletisiyle herhangi bir yerde yığın izlemesi ve kod yoktur. Ben "Uyarı" ve "Mümkün" büyük W ve P olsun, bu yüzden farklı bir hata olabilir düşünüyorum. Birden fazla olay dinledim, ama ben sadece her seferinde .on'u çağırıyorum, bu yüzden sorunun ne olduğundan emin değilim.
Phil

2
@ Phil_1984_ Bir çözüm buldunuz mu? eğer bu işe yaramıyor gibi görünüyor - stackoverflow.com/questions/38482223/…
Yoni Jah

3
İlk yorumun bağlantısı FYI (jongleberry.com) çevrimdışı. Arşivlenen sürüm: web.archive.org/web/20180315203155/http://www.jongleberry.com/…
Jeff Ward

76

Varsayılan olarak, herhangi bir etkinlik için en fazla 10 dinleyici kaydedilebilir.

Kodunuz buysa, maxListeners'ı şu yollarla belirtebilirsiniz:

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

Ancak kodunuz değilse, varsayılan sınırı global olarak artırmak için hileyi kullanabilirsiniz:

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

Elbette sınırları kapatabilirsiniz, ancak dikkatli olun:

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

BTW. Kod uygulamanın en başında olmalıdır.

EKLE: 0.11 düğümünden beri bu kod varsayılan sınırı değiştirmek için de çalışır:

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

5
5.6.0 Düğümünde benim için çalışan tek çözüm buydu. Bir ton teşekkürler!
Andrew Faulkner

Reat-native, düğüm sürümü 8 kullanıyorum. *. *. Bu benim için işe yaramadı.
Thomas Valadez

mayın zorunludur ('olaylar') EventEmitter.defaultMaxListeners = Infinity;
Karl Anthony Baluyot

73

Kabul edilen cevap, sınırın nasıl artırılacağına ilişkin anlambilim sağlar, ancak @voltrevo, uyarının bir nedenden dolayı olduğunu ve kodunuzun muhtemelen bir hata olduğunu belirtti.

Aşağıdaki buggy kodunu düşünün:

//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');
}

Şimdi dinleyiciyi eklemenin doğru yolunu izleyin:

//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'ı değiştirmeden önce kodunuzdaki benzer sorunları arayın (diğer yanıtlarda açıklanmaktadır)


13
bu cevap, uyarı ve bunun nasıl çözüleceğinin gerçek nedenini gösterdiği için kabul edilmelidir, +1
Ganesh Karewad

Bu doğru cevap! Dürüst olmak gerekirse, maxListener uyarısı çoğunlukla bazı buggy kodları nedeniyle göründüğünü düşünüyorum. Benim durumumda mysql kodu oldu. Bunun için açıklık getirmek için bir cevap vermeye çalışacağım.
Adrian

25

Değiştir .on()ile once(). Kullanılması once(), olay aynı işlev tarafından işlendiğinde olay dinleyicilerini kaldırır.

Bu sorunu çözmezse, paketleyiciyi bununla paketinize yeniden yükleyin. Json "restler": "git: //github.com/danwrong/restler.git#9d455ff14c57ddbe263dbbcd0289d76413bfe07d"

Bu, düğüm 0.10 ile yanlış davranan restler ile ilgilidir. sorunun git'te burada kapandığını görebilirsiniz: https://github.com/danwrong/restler/issues/112 Ancak npm henüz bunu güncellemedi, bu yüzden git başına başvurmanız gerekiyor.


Bu Puppeterr framework
C Alonso C Ortega


4

Düğüm Sürümü: v11.10.1

Yığın izlemesinden gelen uyarı mesajı:

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 sorunları, belgeler ve benzer olay yayıcı bellek sızıntıları oluşturulduktan sonra, iOS push bildirimi için kullanılan düğüm apn modülü nedeniyle bu sorun gözlendi .

Bu çözdü:

Sahip olduğunuz her sertifika / anahtar çifti için işlem başına yalnızca bir Sağlayıcı oluşturmanız gerekir. Her bildirim için yeni bir Sağlayıcı oluşturmanız gerekmez. Yalnızca bir uygulamaya bildirim gönderiyorsanız, birden fazla Sağlayıcıya gerek yoktur.

Uygulamanızda sürekli Sağlayıcı örnekleri oluşturuyorsanız, kaynaklarını ve belleğini serbest bırakmak için her sağlayıcıyla işiniz bittiğinde Provider.shutdown () yöntemini çağırdığınızdan emin olun.

Bildirim her gönderildiğinde sağlayıcı nesnesi oluşturuyordum ve gc'nin temizlemesini bekliyordum.


2

Benim durumumda child.stderr.pipe(process.stderr) çocuğun 10 (veya daha fazla) örneğini başlatırken çağrıldım. Bu nedenle, bir LOOP'daki aynı EventEmitter Nesnesine bir olay işleyicisi eklemeye yol açan her şey, düğümlerin bu hatayı atmasına neden olur.


2

Bazen bu uyarılar yaptığımız bir şey değil, yapmayı unuttuğumuz bir şey olduğunda ortaya çıkar!

Dotenv paketini npm ile yüklediğimde bu uyarıyla karşılaştım, ancak uygulamamın başlangıcında requir ('dotenv'). Load () ifadesini eklemeye başlamadan önce kesildim. Projeye döndüğümde, "Olası EventEmitter bellek sızıntısı algılandı" uyarılarını almaya başladım.

Sorunun yaptığım bir şeyden olduğunu varsaydım, yapmadığım bir şey değil!

Gözetimimi keşfettiğimde ve zorunlu ifadeyi eklediğimde, bellek sızıntısı uyarısı temizlendi.


2

Mümkün olduğunca günlükleri bastırmak yerine avlanmayı ve sorunları gidermeyi tercih ederim. Uygulamamda bu sorunu gözlemledikten birkaç gün sonra req.socket, bir Express ara katmanındaki dinleyicileri ortaya çıkmaya devam eden soket hatalarını yakalamak için ayarladığımı fark ettim . Bir noktada bunun gerekli olmadığını öğrendim, ama dinleyicileri yine de tuttum. Sadece kaldırdım ve yaşadığınız hata ortadan kalktı. Aşağıdaki middleware ile ve olmadan benim sunucuya istekleri çalıştırarak nedeni olduğunu doğruladı:

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();
    }

Bu ara katman yazılımını kaldırmak gördüğünüz uyarıyı durdurdu. Kodunuzun etrafına bakın ve ihtiyacınız olmayan dinleyicileri ayarlayabileceğiniz herhangi bir yeri bulmaya çalışacağım.


1

aynı sorunu yaşıyordum. ve sorun, 2 dinleyicide 8080 numaralı bağlantı noktasını dinlediğimden kaynaklandı.

setMaxListeners() iyi çalışıyor, ama ben tavsiye etmem.

doğru yol, ekstra dinleyiciler için kodunuzu kontrol etmek, dinleyiciyi kaldırmak veya dinlediğiniz port numarasını değiştirmek, bu benim sorunumu çözdü.


1

Başladığım zamana kadar bunu yapıyordum grunt watch. Sonunda tarafından çözüldü

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

Can sıkıcı mesaj gitti.


1

Şunları kullanarak yenilerini oluşturmadan önce tüm dinleyicileri temizlemeniz gerekir:

Müşteri sunucusu

socket.removeAllListeners(); 

Soketin istemci soketiniz / veya oluşturulan sunucu soketiniz olduğu varsayılır.

Dinleyiciyi şu şekilde kaldırmak gibi belirli olay dinleyicilerinden de abone olabilirsiniz connect:

this.socket.removeAllListeners("connect");

0

process.on('uncaughtException', callback);
Bu ifadeyi nerede kullanıyorsunuz dediniz ? Geçilen geri arama dahilinde http.createServermi?
Evet ise, aynı callback'inde farklı kopya bağlı alacak uncaughtException çünkü her yeni talep üzerine olay function (req, res) { ... }yürütülen her şey olur, yeni bir istek gelir ve böylece irade beyanı process.on('uncaughtException', callback);
olduğunu Not süreç nesne küresel olan tüm istekleri ve ekleme dinleyiciye yeni bir istek geldiğinde etkinliğe mantıklı gelmez. Böyle bir davranış istemeyebilirsiniz.
Her yeni istek için yeni bir dinleyici eklemek isterseniz, etkinliğe eklenmiş önceki dinleyicileri artık aşağıdakileri kullanarak gerekmeyeceklerinden kaldırmalısınız:
process.removeAllListeners('uncaughtException');


0

Ekibimizin bunun için düzeltmesi, .npmrc dosyamızdan bir kayıt defteri yolunu kaldırmaktı. Rc dosyasında iki yol takma adı vardı ve bunlardan biri kullanımdan kaldırılmış bir Yapay örneğe işaret ediyordu.

Hatanın Uygulamamızın gerçek koduyla ilgisi yoktu ama geliştirme ortamımızla ilgili her şey vardı .


0

Aynı sorunla karşı karşıya kaldım, ancak asenkron beklemeyle başarılı bir şekilde başa çıktım.
Lütfen yardımcı olup olmadığını kontrol edin.

veri uzunluğu = 25;
Önce:
  için (let i = 0; i <dataLength; i ++) {
      sftp.get (remotePath, fs.createWriteStream ( xyzProject/${data[i].name}));
  }

Sonra:
  for (let i = 0; i <dataLength; i ++) {
      await sftp.get (remotePath, fs.createWriteStream ( xyzProject/${data[i].name}));
  }


0

Uyarının gerçek problemini / kök nedenini nasıl çözeceğime dair bir fikir verdiğim için RLaaa'ya teşekkürler . Benim durumumda MySQL buggy kodu oldu.

İçinde böyle bir kodla bir Promise yazdığınız takdirde:

pool.getConnection((err, conn) => {

  if(err) reject(err)

  const q = 'SELECT * from `a_table`'

  conn.query(q, [], (err, rows) => {

    conn.release()

    if(err) reject(err)

    // do something
  })

  conn.on('error', (err) => {

     reject(err)
  })
})

Kodda bir conn.on('error')dinleyici olduğuna dikkat edin . Kelimenin tam anlamıyla tekrar tekrar dinleyen bu kod, sorguyu kaç kez çağırdığınıza bağlıdır. Bu arada if(err) reject(err)aynı şeyi yapar.

Böylece conn.on('error')dinleyiciyi çıkardım ve sesimi çözdüm! Umarım bu size yardımcı olur.


-4

Bunu server.js'nin (veya ana Node.js uygulamanızı içeren her şeyi) ilk satırına yerleştirin:

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

ve hata gider :)


Bana bir ana dosyaya koymam için bir fikir verdin ve işe yaradı. Sadece yanlış bir yere koyuyordum. Teşekkürler!
sklimkovitch
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.