Uh oh!
There was an error while loading. Please reload this page.
http: fixes memory retention issue with FreeList and HTTPParser - #33190
http: fixes memory retention issue with FreeList and HTTPParser#33190leidegre wants to merge 1 commit into
Conversation
Adding this for clarification. This isn't a strict memory leak issue. There's an upper limit to the free list of a 1000 entries, which means that at most, it will retain up to 1000 times whatever the amount of bytes retained by event handlers. In our case this was about 1.5 MB (our heap usage eventually grew to about 1.5 GB as the free list is filled up when the site is under heavier load, this takes several days to happen). This issue has resulted in production outages due to memory starvation and I'm very eager to get this fixed. |
Trott
left a comment
There was a problem hiding this comment.
Not a blocker to landing this, but is it possible to add a test?
Trott
commented
May 2, 2020
@nodejs/http |
Trott
commented
May 2, 2020
@leidegre Thanks for all the work you did to track this down! |
@Trott Thanks. I understand the desire to add a test but I'm not sure how I would go about that in a meaningful manner given the particulars of the code changes. It would be a lot of work for me to make a meaningful contribution. I would be happy to verify any commits/builds though. |
lpinca
commented
May 2, 2020
@leidegre it should be sufficient to verify that Anyway it can be added also in follow up PR. |
@leidegre feel free to add the following test under 'use strict';constcommon=require('../common');constassert=require('assert');consthttp=require('http');const{ HTTPParser }=require('_http_common');// Test that the `HTTPParser` instance is cleaned up before being returned to// the pool to avoid memory retention issues.constkOnTimeout=HTTPParser.kOnTimeout|0;constserver=http.createServer();server.on('request',common.mustCall((request,response)=>{constparser=request.socket.parser;assert.strictEqual(typeofparser[kOnTimeout],'function');request.socket.on('close',common.mustCall(()=>{assert.strictEqual(parser[kOnTimeout],null);}));response.end();server.close();}));server.listen(common.mustCall(()=>{constrequest=http.get({port: server.address().port});letparser;request.on('socket',common.mustCall(()=>{parser=request.parser;assert.strictEqual(typeofparser.onIncoming,'function');}));request.on('response',common.mustCall((response)=>{response.resume();response.on('end',common.mustCall(()=>{assert.strictEqual(parser.onIncoming,null);}));}));})); |
d5cf198 to
85b3bd7Compare@lpinca Thanks! I've included the test in the PR (I've amended this commit). I've also verified that the test fails with Node 14 and that it succeeds with these changes applied. The test is here test/parallel/test-http-parser-memory-retention.js. |
85b3bd7 to
5057d36Comparenodejs-github-bot
commented
May 3, 2020
nodejs-github-bot
commented
May 4, 2020
This is currently an issue with Node 12 (as well as 14) so I was wondering what the process is for landing this in 12 (given that it's the current LTS) and that 14 will become the next LTS? Do I need to do something for this to happen or will this be added to some list and integrated into the next release? |
@addaleax Mind reader! 👍 |
addaleax
commented
May 4, 2020
Commits are backported to LTS by default, so unless there are merge conflicts, no. If there are merge conflicts, you will be pinged, though. Also, just so you know, as a rule commits have to be released for 2 weeks in a Current (i.e. 14.x) release before they are backported to LTS release lines. I’ve added the lts-watch label, but that’s more in order to make sure that this is taken into consideration and to explicitly mark this as something that should land on lts-v12.x.
I just saw your comment, that’s all 😄 |
leidegre
commented
May 5, 2020
Looks like some of the checks have failed with some transient Git issue? I don't know if I can do anything about it... |
nodejs-github-bot
commented
May 5, 2020
leidegre
commented
May 5, 2020
Everything good now? |
Fixes: #29394 Refs: #33167 (comment) PR-URL: #33190 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Flarna
commented
May 5, 2020
Landed in 26f1500 |
Fixes: #29394 Refs: #33167 (comment) PR-URL: #33190 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
codebytere
commented
Jun 7, 2020
Backport currently blocked on #32329. |
leidegre
commented
Jun 7, 2020
@codebytere This is important to me. Is there anything I can do to unblock this? |
codebytere
commented
Jun 7, 2020
Fixes: #29394 Refs: #33167 (comment) PR-URL: #33190 Reviewed-By: Robert Nagy <ronagy@icloud.com> Reviewed-By: Luigi Pinca <luigipinca@gmail.com> Reviewed-By: Juan José Arboleda <soyjuanarbol@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Rich Trott <rtrott@gmail.com> Reviewed-By: Gerhard Stöbich <deb2001-github@yahoo.de>
Fixes: #29394
Refs: #33167 (comment)
The issue here is that because the HTTPParser is pooled it has the possibility to act as a retainer of a lot of data. In summary we have to reset
parser.onIncomingandparser[kOnTimeout]tonullto prevent these from retaining memory while the HTTPParser is sitting in the FreeList unused.I'd like this to eventually be cherry picked into the Node 14 release.
See the reference for details.
@ronag Here's your PR.