Permalink
Browse files

events: make memory leak warning more accessible

This makes the famous `EventEmitter memory leak` warnings occurring
when the listener count for a given event exceeds a specified number
more programatically accessible, by giving them properties referring
to the event emitter instance and the event itself.

This can be useful for debugging the origins of such a warning when
the stack itself doesn’t reveal enough information about the event
emitter instance itself, e.g. when manual inspection of the
already-registered listeners is expected to be useful.

PR-URL: #8298
Reviewed-By: Colin Ihrig <cjihrig@gmail.com>
Reviewed-By: James M Snell <jasnell@gmail.com>
Reviewed-By: Jeremiah Senkpiel <Fishrock123@rocketmail.com>
  • Loading branch information...
addaleax authored and Fishrock123 committed Aug 27, 2016
1 parent 354166c commit 605db31fe73a2b5f15dd7362698f1ef5b1ceb420
Showing with 37 additions and 1 deletion.
  1. +10 −0 doc/api/events.md
  2. +6 −1 lib/events.js
  3. +21 −0 test/parallel/test-event-emitter-max-listeners-warning.js
View
@@ -278,6 +278,14 @@ emitter.once('event', () => {
});
```
The [`--trace-warnings`][] command line flag can be used to display the
stack trace for such warnings.
The emitted warning can be inspected with [`process.on('warning')`][] and will
have the additional `emitter`, `type` and `count` properties, referring to
the event emitter instance, the event’s name and the number of attached
listeners, respectively.
### emitter.addListener(eventName, listener)
<!-- YAML
added: v0.1.26
@@ -562,4 +570,6 @@ Returns a reference to the `EventEmitter`, so that calls can be chained.
[`emitter.listenerCount()`]: #events_emitter_listenercount_eventname
[`domain`]: domain.html
[`process` object's `uncaughtException` event]: process.html#process_event_uncaughtexception
[`process.on('warning')`]: process.html#process_event_warning
[stream]: stream.html
[`--trace-warnings`]: cli.html#cli_trace_warnings
View
@@ -256,9 +256,14 @@ function _addListener(target, type, listener, prepend) {
m = $getMaxListeners(target);
if (m && m > 0 && existing.length > m) {
existing.warned = true;
process.emitWarning('Possible EventEmitter memory leak detected. ' +
const w = new Error('Possible EventEmitter memory leak detected. ' +
`${existing.length} ${type} listeners added. ` +
'Use emitter.setMaxListeners() to increase limit');
w.name = 'Warning';
w.emitter = target;
w.type = type;
w.count = existing.length;
process.emitWarning(w);
}
}
}
@@ -0,0 +1,21 @@
// Flags: --no-warnings
// The flag suppresses stderr output but the warning event will still emit
'use strict';
const common = require('../common');
const events = require('events');
const assert = require('assert');
const e = new events.EventEmitter();
e.setMaxListeners(1);
process.on('warning', common.mustCall((warning) => {
assert.ok(warning instanceof Error);
assert.strictEqual(warning.name, 'Warning');
assert.strictEqual(warning.emitter, e);
assert.strictEqual(warning.count, 2);
assert.strictEqual(warning.type, 'event-type');
}));
e.on('event-type', function() {});
e.on('event-type', function() {});

0 comments on commit 605db31

Please sign in to comment.