-
Notifications
You must be signed in to change notification settings - Fork 1.6k
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
[vm/ffi] Enable sending NativeFinalizer
s over Isolate.exit
?
#55050
Comments
If you have a finalizer attached to an object, and you send that object through (I should check.) But this is about native finalizers, which only do callouts to native functions, right? Here it also matters what happens on Sending (merging) the native finalizer to another isolate with (Why does a native finalizer need an isolate reference? Is the native code run in a way that makes it being to that isolate?) Whether an exit message is handled shouldn't matter. It exists, and is delivered. Whether someone looks at it after that is up to them. If it languishes in the buffer of a paused The |
Thanks for all the good questions @lrhn! I think I have a slightly better idea flashed out now. See my answers to your questions below.
Heap merging yes, but if that finalizer is not saved in a global variable or something, it will be GCed itself. Finalizers that are GCed will never be run.
Conceptually only a native function is called. Implementation detail is that the finalizer entries need to be removed from the Dart heap, otherwise we would leak memory by accumulating entry objecs. So currently, a message is sent to the isolate to do so. If we were able to remove entries from a Dart sdk/sdk/lib/_internal/vm/lib/internal_patch.dart Lines 268 to 289 in 3ef08e1
It will trigger. We don't want it to quietly go away, it would lead to leaking native resources.
I don't think we can achieve that sending or not sending doesn't change the behavior. We have specified for both So sending the native finalizer to a new isolate prevents the native callbacks from being run eagerly. So the behavior is different between sending and not sending. (Having
I guess if a message is not handled, but stays in flight forever, it does keep all the objects in such message alive, including the If we change the
That is a good question. Alternatively, calling High level idea then:
|
From a discussion with @HosseinYousefi:
|
If we have an object sharable across isolates, that object doesn't have an owning isolate. If this sharable object represents a resource, the resource is owned by the isolate group - not by an individual isolate. => We may want to disallow attaching native finalizers (with run-eagerly-on-isolate-shutdown semantics) to sharable objects. |
This is somewhat of a separate issue, but may be worthwhile fixing. Already today one can create deeply immutable objects (dart constants, but also deeply immutable typed data arrays). Attaching finalizers to them seems not a good idea. @dcharke could you make a CL to disallow that? |
Okay, I think the conclusion is that we do not want to support sending |
After https://dart-review.googlesource.com/c/sdk/+/354902, we will allow sending deeply immutable
Finalizable
s to other isolates in the same group. However, if aNativeFinalizer
lives in an isolate that exits, but deeply immutableFinalizable
s are still alive in other isolates, the native resources are prematurely finalized. Therefore, we should enable sendingNativeFinalizer
s to another isolate viaIsolate.exit
.Currently, sending
NativeFinalizers
s is disallowed:sdk/runtime/vm/object_graph_copy.cc
Line 873 in 83ba591
sdk/runtime/vm/isolate.cc
Line 2389 in 83ba591
Sending a
NativeFinalizer
to another isolate should have the effect of changing the isolate pointer to the receiving isolate.Some open questions:
If we do decide to support this, maybe we should add a
NativeFinalizer.adopt(NativeFinalizer other)
that will check if the native callback function is equal and then merge all the entries from the other finalizer. This will enable storing a finalizer in a static field and on isolate shutdown sending it to another isolate and merging it into the finalizer that's in the "same" static field already. (The alternative is that one might have a collection of adopted finalizers and can never clean up that collection.)If we do not decide to support it, probably the best practise is that
NativeFinalizer
s should live on, andFinalizable
s should be created on, an isolate that will stay alive until the end of the program (the main isolate or platform isolate). cc @liamappelbe @HosseinYousefi Do you have use cases where you want to create aFinalizable
on a helper isolate that is subsequently going to exit after you've sent theFinalizable
to the main isolate?cc @mkustermann @mraleph
(Things would be much easier if we could just mark the
NativeFinalizer
static field asshared
across all isolates in the group, a la dart-lang/language#3531,shared final NativeFinalizer = ...
. We would not need to worry about sending it to another isolate on exit.)The text was updated successfully, but these errors were encountered: