-
-
Notifications
You must be signed in to change notification settings - Fork 31.7k
domain: avoid circular memory references #25993
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
Conversation
Add a simple `WeakReference` utility that we can use until the language provides something on its own.
Avoid circular references that the JS engine cannot see through because it involves an `async id` ⇒ `domain` link. Using weak references is not a great solution, because it increases the domain module’s dependency on internals and the added calls into C++ may affect performance, but it seems like the least bad one. Fixes: nodejs#23862
This approach looks fine to me, given the current situation. How does the memory profile for this look like? E.g., taken the example from #23862 as-is, and hammering it with GET requests, how high would the memory usage be with and without domains usage on the server side? |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM as much as I don't like it. At least it fixes a bad bug.
@ChALkeR What I’m getting is about 8 kB per request with that example before this patch, and flat memory usage afterwards. |
That is what I was expecting, but I was curious about the exact memory usage profile with/without domains code on the server logic side (with this patch enabled) for the same requests pattern. Anyway, this change looks good to me in approach and code-wise. I have not tested this locally (yet?), but this should be good once CI passes. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I'm not sure I understand the API of WeakReference
. Could you write a cctest for it?
I don’t think a cctest makes sense, but I could write a regular test if you feel that it’s important. |
If we want to reuse this is other code path I think we should cover the API. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
LGTM. Technically this would mean that CLS-like implementation based on Async Hooks should be rewriten ovev domain as there is no mem leak anymore here.
@refack I think we want to avoid that as much as possible. I’ve added a test, though.
@vdeturckheim No, that’s not necessarily true. The problem here is specific to domains, because they (needlessly?) keep references to objects that they track. Ideally, we’d revert this change and remove |
(That’s doesn’t mean that it’s not easy to run into memory leaks when using async_hooks, but that’s a fundamental design flaw and a much bigger issue.) |
@@ -53,20 +57,22 @@ const asyncHook = createHook({ | |||
init(asyncId, type, triggerAsyncId, resource) { | |||
if (process.domain !== null && process.domain !== undefined) { | |||
// If this operation is created while in a domain, let's mark it | |||
pairing.set(asyncId, process.domain); | |||
pairing.set(asyncId, process.domain[kWeak]); |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it conceivable that user code tampers with process.domain
?
What would happen if I set process.domain = {}
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I don’t think the domain code is all that tampering-proof to being with…
I’m also not sure what we could do in that case.
static void Get(const FunctionCallbackInfo<Value>& args) { | ||
WeakReference* weak_ref = Unwrap<WeakReference>(args.Holder()); | ||
Isolate* isolate = args.GetIsolate(); | ||
if (!weak_ref->target_.IsEmpty()) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Technically not necessary: Persistent<T>::Get()
will return an empty handle, causing ReturnValue<T>::Set()
to default to undefined
.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Thought about it, and I think I’d prefer an explicit variant here, so that it’s a bit more obvious what happens when the object has been GC’ed…
Add a simple `WeakReference` utility that we can use until the language provides something on its own. PR-URL: #25993 Fixes: #23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
Avoid circular references that the JS engine cannot see through because it involves an `async id` ⇒ `domain` link. Using weak references is not a great solution, because it increases the domain module’s dependency on internals and the added calls into C++ may affect performance, but it seems like the least bad one. PR-URL: #25993 Fixes: #23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
Is this fix planned to be back-ported to the v10 release? |
Any update if this will be backported to LTS? |
Add a simple `WeakReference` utility that we can use until the language provides something on its own. PR-URL: nodejs#25993 Fixes: nodejs#23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
Avoid circular references that the JS engine cannot see through because it involves an `async id` ⇒ `domain` link. Using weak references is not a great solution, because it increases the domain module’s dependency on internals and the added calls into C++ may affect performance, but it seems like the least bad one. PR-URL: nodejs#25993 Fixes: nodejs#23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
Backport opened in #27749 |
Add a simple `WeakReference` utility that we can use until the language provides something on its own. Backport-PR-URL: #27749 PR-URL: #25993 Fixes: #23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
Avoid circular references that the JS engine cannot see through because it involves an `async id` ⇒ `domain` link. Using weak references is not a great solution, because it increases the domain module’s dependency on internals and the added calls into C++ may affect performance, but it seems like the least bad one. Backport-PR-URL: #27749 PR-URL: #25993 Fixes: #23862 Reviewed-By: Matteo Collina <matteo.collina@gmail.com> Reviewed-By: Ruben Bridgewater <ruben@bridgewater.de> Reviewed-By: Сковорода Никита Андреевич <chalkerx@gmail.com> Reviewed-By: Vladimir de Turckheim <vlad2t@hotmail.com> Reviewed-By: Colin Ihrig <cjihrig@gmail.com> Reviewed-By: Ben Noordhuis <info@bnoordhuis.nl> Reviewed-By: Refael Ackermann <refack@gmail.com>
src: add WeakReference utility
Add a simple
WeakReference
utility that we can use until thelanguage provides something on its own.
domain: avoid circular memory references
Avoid circular references that the JS engine cannot see through
because it involves an
async id
⇒domain
link.Using weak references is not a great solution, because it increases
the domain module’s dependency on internals and the added calls into
C++ may affect performance, but it seems like the least bad one.
Fixes: #23862
Checklist
make -j4 test
(UNIX), orvcbuild test
(Windows) passes