-
Notifications
You must be signed in to change notification settings - Fork 30k
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
Keepalive prevents garbage collection on unread responses #29394
Comments
Related: #29118 |
I'm not sure but we might be missing a: const parser = socket.parser;
if (parser) {
parser.finish();
freeParser(parser, req, socket);
} In a few places. Not sure if the parser should be freed before the socket is put into the agent pool through Possible places that need it (i.e. before either responseOnEnd
responseKeepAlive
onSocketNT @addaleax: How does parser allocation/deallocation work? Do we need to free the parser for: A. destroyed sockets? |
CC: @brandonstark, @yoshigev |
Please add also |
+1 |
@orgads: I'm sorry. I can't help until I get some further clarification myself. |
@ronag The HTTP code as never written very cleanly, and it wouldn’t be surprising if something’s missing here. I don’t think we need to free the parser for re-used sockets; afaik, it is built with the intention of being able to parse multiple HTTP messages on one socket in mind. |
Any progress? |
Is the added benefit of object pooling here really motivated given all the added complexity? I was able to trace this back to this commit (which is over 10 years old) but I could not find any motivation for why it was deemed necessary. Is object construction (in this particular case) so expensive that this actually has a tangible performance impact? V8 has changed so much since then that I have to assume that any assumptions made back then won't hold today. Would it be possible to just remove the object pooling altogether? I stumbled into this because of a memory leak issue, and the |
I'd like to share some additional details from one of our production environments. In our particular case there's a payload of about 1.5 MB that is being retained for each This problem is exacerbated in our case because the large payload is being retained in a The big drops in memory usage are restarts. |
Free parser when putting socket back in the agent keep alive free list. Fixes: nodejs#29394
@ronag will give it a go. Meanwhile, I've been trying to figure out why it's retaining so much data. It's a big app and the problem doesn't reproduce easily, I've tried various repos for a while now without any luck. The only thing I can tell from this picture is that somehow the majority of bytes are being retained in the * the red stuff is my code. |
@ronag is it possible to load core modules from external file instead, since this is just a change in Node.js JavaScript core module... build everything from scratch is a bit of chore. Happy to do it but it's going to take some time.
|
No idea, not familiar with this.
I'm happy to wait 😄 |
We did some work on this and uncovered some stuff. The are additional references There are two options here.
|
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) 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>
If keepAlive is enabled for the agent, and the response is not read by the client, the memory consumption grows very fast.
This is possibly similar (but not caused by) to recent fixes like #29297 and its predecessors.
If I uncomment
res.resume()
(or comment outkeepAlive
) then memory consumption is sane (around 120M). But when it is commented out, memory usage reaches 280M.Using the inspector, I see that there are many stale Socket objects, which are retained by onIncoming in HTTPParser in FreeList. There are no application retainers. The application has no access to this IncomingMessage since it is not stored anywhere by the application, so it should be garbage collected eventually.
It looks like after a lot of time, this HTTPParser is reallocated for another request, and only then this response is GC'ed.
The text was updated successfully, but these errors were encountered: