Skip to content

High memory usage for upgraded http requests#11868

@lpinca

Description

@lpinca
  • Version:
    v7.7.3
  • Platform:
    macOS/Linux
  • Subsystem:
    net/http

I noticed that n socket connections obtained with the HTTP upgrade mechanism use a lot more memory than n socket connections obtained with a plain net server. Consider for example the following test.

net server
'use strict';constnet=require('net');constheaders=['HTTP/1.1 101 Switching Protocols','Connection: Upgrade','Upgrade: foo','',''].join('\r\n');letcount=0;consthandler=(socket)=>{socket.resume();socket.write(headers);if(++count===150000){gc();constrss=process.memoryUsage().rss;console.log(rss/1024/1024);}};constserver=net.createServer({allowHalfOpen: true});server.on('connection',handler);server.listen(3000,()=>console.log('listening on *:3000'));
net client
'use strict';constnet=require('net');constheaders=['GET / HTTP/1.1','Connection: Upgrade','Upgrade: foo','Host: localhost:3000','',''].join('\r\n');leti=0;(functioncreateClient(){constsocket=net.connect({localAddress: `127.0.0.${i%100+1}`,port: 3000});socket.on('connect',()=>{socket.resume();socket.write(headers);if(++i===150000)return;createClient();});})();
http server
'use strict';consthttp=require('http');constheaders=['HTTP/1.1 101 Switching Protocols','Connection: Upgrade','Upgrade: foo','',''].join('\r\n');letcount=0;consthandler=(req,socket,head)=>{socket.resume();socket.write(headers);if(++count===150000){gc();constrss=process.memoryUsage().rss;console.log(rss/1024/1024);}};constserver=http.createServer();server.setTimeout(0);server.on('upgrade',handler);server.listen(3000,()=>console.log('listening on *:3000'));
http client
'use strict';consthttp=require('http');leti=0;(functioncreateClient(){constreq=http.get({localAddress: `127.0.0.${i%100+1}`,port: 3000,headers: {'Connection': 'Upgrade','Upgrade': 'foo'}});req.on('upgrade',(res,socket,head)=>{socket.resume();if(++i===150000)return;createClient();});})();

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

socket.removeAllListeners('drain');socket.removeAllListeners('error');socket.removeAllListeners('timeout');

in the upgrade event handler, memory usage drops to ~420 MiB.

Metadata

Metadata

Assignees

No one assigned

    Labels

    httpIssues or PRs related to the http subsystem.memoryIssues and PRs related to the memory management or memory footprint.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions