-
Notifications
You must be signed in to change notification settings - Fork 29.8k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in 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: