Open dcharkes opened 5 months ago
A native finalizer triggers on an object being unreachable.
Currently we assume that isolate shutdown makes every object in the isolate unreachable (and Isolate.exit
is treated as a very efficient copy, I guess).
If a variable is shared, its value is shared, and will not become (globally) unreachable if one isolate shuts down. That seems reasonable.
If, big if, we introduce shared variables, and therefore shared values, we should perhaps have shared finalizers too. (If the finalizer object is not shared, it would die with the isolate? So it should be stored in a shared variable too?)
So a separate constructor, or even a separate class with its own documentation, which would answer the question here.
Some notes from discussion @mkustermann and @mraleph:
Sharable and isolate local constructor:
Sharable
interface for shared memory multi-threading, it would make sense to have NativeFinalizer.shared
because we can check that only sharable objects get attached to that one and only non-sharable objects get attached to the local NativeFinalizer
.Sharable
interface, then we'd likely only want a single shared
constructor for NativeFinalizer
s. And every developer should only store NativeFinalizer
s in shared
static variables.NativeFinalizer
s being GCable:
NativeFinalizer
semantics to not be detached when the NativeFinalizer
object itself is GCed, then basically all attach
events to NativeFinalizer
s work like being attached to a shared
NativeFinalizer
.detach
would not work shared. Trying to detach
from a non-shared static nativeFinalizer
would lead to a no-op on another isolate. Because it would be a different native finalizer (that happens to have the same callback address.)
Currently, the documentation states that native finalizers will be run before isolate group shutdown.
The implementation currently guarantees that native finalizers are run on isolate shutdown.
Currently we under-promise, and over-deliver. It might be useful to actually promise run on isolate shutdown. This way users using the isolate APIs can use native finalizers freeing up globals in native code and reuse that native code when a new isolate is started.
Thanks for reporting @mraleph!
@lrhn Any concerns about over-promising things?
Side note: Shared (isolate group) native finalizers
If in the future we introduce
shared
variables, we'd likely want to have a type of native finalizer that is only guaranteed to run on isolate group shutdown. For such shared native finalizers, we might need a different constructor:If we were to introduce a native finalizer shared in an isolate group with a different constructor, we'd need to update the doc comments to reflect these two different shutdown guarantees for shared and non-shared native finalizers.
The current workaround without the
shared
keyword is to useDart_FinalizableHandle
s from thedart_api.h
, these are isolate group scoped instead of isolate scoped.Edit, also see: