-
Notifications
You must be signed in to change notification settings - Fork 30.7k
New issue
Have a question about this project? # for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “#”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? # to your account
High memory usage for upgraded http requests #11868
Comments
After digging a little more, I noticed that memory usage drops to ~275 MiB if all listeners are removed from the socket. This made me think that it must be something to do with the default I tried to remove and readd them to the socket in the const end = socket.listeners('end')[0];
const _socketEnd = socket.listeners('_socketEnd')[0];
const finish = socket.listeners('finish')[0];
socket.removeAllListeners('end');
socket.removeAllListeners('_socketEnd');
socket.removeAllListeners('finish');
socket.once('end', end);
socket.on('_socketEnd', _socketEnd);
socket.on('finish', finish); and with my big surprise memory usage is now ~300 MiB (the same amount used by the plain net server). To summarize, in order to make the
Does anyone know and care to explain why this happens? |
Prevent the events listeners of the sockets obtained with the HTTP upgrade mechanism from retaining unneeded memory. Refs: nodejs#11868
A small update here after #11926 which partially fixed this. It seems that the additional, remaining, memory is retained by instances of EventHandlers. 'use strict';
const EE = require('events');
const _socketEnd = () => {};
const end = () => {};
const finish = () => {};
const ondrain = () => {};
const socketOnClose = () => {};
const socketOnData = () => {};
const socketOnDrain = () => {};
const socketOnEnd = () => {};
const socketOnError = () => {};
const socketOnPause = () => {};
const socketOnResume = () => {};
const socketOnTimeout = () => {};
const arr = [];
for (var i = 0; i < 1000000; i ++) {
const ee = new EE();
ee.on('_socketEnd', _socketEnd);
ee.on('finish', finish);
ee.once('end', end);
ee.on('error', socketOnError);
ee.on('timeout', socketOnTimeout);
arr.push(ee);
}
setInterval(() => {
const l = arr.length;
gc();
console.log(process.memoryUsage().rss / 1024 / 2014);
}, 30000); It produces the following results.
If I add and remove the additional listeners like it is done in $ diff -u a.js b.js
--- a.js 2017-03-25 16:01:39.000000000 +0100
+++ b.js 2017-03-25 15:34:34.000000000 +0100
@@ -20,12 +20,32 @@
for (var i = 0; i < 1000000; i ++) {
const ee = new EE();
+ // Default socket events listeners.
ee.on('_socketEnd', _socketEnd);
ee.on('finish', finish);
ee.once('end', end);
+
+ // Listeners added in _http_server.js
ee.on('error', socketOnError);
ee.on('timeout', socketOnTimeout);
+ // Listeners added and removed in _http_server.js
+ ee.on('close', socketOnClose);
+ ee.on('data', socketOnData);
+ ee.on('drain', ondrain);
+ ee.on('drain', socketOnDrain);
+ ee.on('end', socketOnEnd);
+ ee.on('pause', socketOnPause);
+ ee.on('resume', socketOnResume);
+
+ ee.removeListener('close', socketOnClose);
+ ee.removeListener('data', socketOnData);
+ ee.removeListener('drain', ondrain);
+ ee.removeListener('drain', socketOnDrain);
+ ee.removeListener('end', socketOnEnd);
+ ee.removeListener('pause', socketOnPause);
+ ee.removeListener('resume', socketOnResume);
+
arr.push(ee);
} I get
With #11930 results are more in line with the expected behavior.
|
@lpinca Did you run those scripts with the various versions of V8 in master? It would be interesting to test master with/without #11930 with each V8: 5.5 (same as v7), 5.6, and recently merged 5.7. This might help narrow down if this was due to some other change in node, due to V8 upgrade, or due to |
Gonna try with more combinations and post back. It will take some time as compiling takes ages. |
With V8 5.4 and 5.5 there is no difference. Something changed in 5.6. |
I'm wondering if 5.6 is when the |
@mscdex not sure how to see that https://codereview.chromium.org/2430273007. |
@lpinca It appears it was first available in 5.6.144 (see the github mirror). Additionally, you can check the output of var obj = Object.create(null);
console.log(%HasFastProperties(obj)); with the |
Prevent the events listeners of the sockets obtained with the HTTP upgrade mechanism from retaining unneeded memory. Ref: nodejs#11868 PR-URL: nodejs#11926 Reviewed-By: James M Snell <jasnell@gmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl>
Closing as everything has been addressed here. |
v7.7.3
macOS/Linux
net/http
I noticed that
n
socket connections obtained with the HTTP upgrade mechanism use a lot more memory thann
socket connections obtained with a plain net server. Consider for example the following test.net server
net client
http server
http client
The first (net) server uses ~295 MiB of memory while the second (http) ~525 MiB. Shouldn't they use more or less the same amount of memory?
It seems that, in part, the difference is caused by the additional event listeners. If I add
in the
upgrade
event handler, memory usage drops to ~420 MiB.The text was updated successfully, but these errors were encountered: