-
Notifications
You must be signed in to change notification settings - Fork 1.7k
Description
Update 2022:
Available in https://api.dart.dev/stable/2.18.3/dart-ffi/NativeFinalizer-class.html.
Update 2020-06-26:
Finalizers are now available in native code (not yet exposed in Dart):
d.lookupFunction<Void Function(Handle), void Function(Object)>("PassObjectToC");
void attachFinalizer(Object o) => passObjectToC(o);
static void RunFinalizer(void* isolate_callback_data,
void* peer) {
printf("Running finalizer.\n");
}
extern "c" void PassObjectToC(Dart_Handle h) {
void* peer = 0x0;
intptr_t size = 8;
auto finalizable_handle = Dart_NewFinalizableHandle_DL(handle_2, peer, size, RunFinalizer);
}
Use dynamic linking (the _DL
suffix) so that the symbols are available in Flutter. See documentation and samples on 7eac9f3 (C code, Dart code).
See more documentation in native_api.h and dart_api_dl.h.
Caveat:
- The dart optimiser can inline method bodies and fields, which means objects can in some cases be GCed (and their finalizer run) before all methods are done executing. When we expose finalizers in Dart, we will have a solution for this. Workaround: do an ffi call with a
Dart_Handle
passing that object to native, that will keep it alive until that call (like a reachability fence). Or alternatively use the Dart calling convention to keep the object alive:@pragma('vm:never-inline') Object reachabilityFence(Object obj) { return obj; }
==========================================================================================
This issue was originally intended to track exposing finalizers in Dart. (The above code exposes finalizers in C.)
A potential API would be.
/// Return a pointer object that has a finalizer attached to it. When this
/// pointer object is collected by GC the given finalizer is invoked.
///
/// Note: the pointer object passed to the finalizer is not the same as
/// the pointer object that is returned from [finalizable] - it points
/// to the same memory region but has different identity.
Pointer<T> finalizable<T>(Pointer<T> p, void finalizer(Pointer<T> ptr)) {
}
However, exposing FFI-specific finalizers in Dart has been superseded by adding finalizers to Dart in general https://github.com/dart-lang/sdk/issues/45455.
Activity
dcharkes commentedon Feb 18, 2019
As discussed with @jonasfj and @mkustermann, maybe it would be better to provide a
Pointer
to a C function as finalizer, as the GC does currently not support running Dart code for finalization.jonasfj commentedon Feb 18, 2019
You might also want to include a
sizeHint
so we can signal an approximate size of the object to the GC.Even if I don't know the exact size of the object I'm holding on to, I know if it's approximately 12 bytes, 12kb, or 12mb give or take a few orders of magnitude.
sjindel-google commentedon Aug 5, 2019
We should implement this in the initial release since so many users seem to need it.
sjindel-google commentedon Aug 26, 2019
I think we should estimate 3 weeks for this, given that we need:
yulingtianxia commentedon Oct 14, 2019
Yeah, we really need it.
ds84182 commentedon Nov 5, 2019
Looking at https://dart-review.googlesource.com/c/sdk/+/123662, I don't think this solves all issues, especially with long lived structures or strings in a static method.
For example, libpng's png_create_read_struct needs the version string of libpng from link-time to ensure that ABI-incompatible changes haven't occurred (https://github.com/glennrp/libpng/blob/libpng16/png.h#L922). Yes, you could also wrap the function with another C library to forward the version correctly, but then you have to make sure that Dart, the auxiliary native library, and libpng are all in sync and are ABI compatible.
I'm just hoping that that CL isn't the final design for pointer finalizers.
derolf commentedon Dec 11, 2019
When will this feature be available?
42 remaining items
mraleph commentedon May 17, 2021
@vaind I think the best you can do right now is the following:
and use this as a replacement for
dart_keepalive
. That should keep theobj
alive (though it will break if we start removing parameters which are never used from functions in AOT compiler, but we don't have any immediate plans to work on something like that AFAIK).vaind commentedon May 17, 2021
Many thanks @mraleph, you saved my day!
skquo commentedon May 22, 2021
What does it mean @dcharkes ? Where can we find
finalizable
?bayo-code commentedon May 23, 2021
There's lots of things about this Finalizer API that I don't understand. If you could help me clarify some of these, I'll be grateful...
Dart_NewPersistentHandle
function returns aDart_PersistentHandle
. What am I supposed to do with it, pass it back to the Dart class that called the function registration routine? If that's the case, does that mean that I would not need the initial object (or pointer) that points to native memory and will instead use whatever is returned by theDart_NewPersistentHandle
in Dart?I'm sorry if these questions sound dumb, it's just that I'm not familiar with the whole Finalizer thing, and I'm trying to make sure that I don't leak memory when I'm working with native code cause I'm creating lots of them
fei4xu commentedon May 25, 2021
I don't like this design and I'm confused: do I need to change the .c code in order to call it from dart? what if the .c lib is a 3rd party library which I don't have source code ?
dcharkes commentedon May 26, 2021
You can write a C library that wraps the original library which attaches the finalizers. And yes, that is not ideal. Multiple packages are facing this issue.
That's why we're investigating adding finalizers in Dart-land. (This issue, #35770, is tracking adding FFI-specific Dart finalizers. However, https://github.com/dart-lang/sdk/issues/45455 proposes to add finalizers to Dart in general.)
Until one of those two issues has been resolved, your options are:
arena
frompackage:ffi
, (2) manual memory management by addingfree
calls in your code, or (3) providing arelease
method in your API that users have to call when done. (Of course there are scenarios in which none of these three work, for example when your objects get passed to a framework that does not tell you when it's done using your object.)dcharkes commentedon May 26, 2021
Yes.
I presume you meant
Dart_NewWeakPersistentHandle
function returns aDart_WeakPersistentHandle
.Or
Dart_NewFinalizableHandle
which returns aDart_FinalizableHandle
.Dart_FinalizableHandle
andDart_PersistentHandle
are used to remove the finalizer if you would want to remove it.If you don't ever want to cancel it, you can ignore the return value of
Dart_NewFinalizableHandle
, because it gets automatically deleted when the object is garbage collected.You should not disregard a
Dart_WeakPersistentHandle
that would leak memory. So I suggest you useDart_FinalizableHandle
s instead.I presume you meant
Dart_NewWeakPersistentHandle
orDart_NewFinalizablePersistentHandle
here.You can pass the
Dart_NewWeakPersistentHandle
orDart_NewFinalizablePersistentHandle
back to the Dart class and store it there as a Pointer. If you'd ever want to cancel the finalizer, you would use that Handle the cancel the finalizer.No problemo!
P.S. These kind of questions are not really issues with Dart. So StackOverflow might be a better place for them than making this GitHub thread very long!
dcharkes commentedon May 26, 2021
This does not exist. This was a proposed API. That will likely never exist because of the pursuit of adding Dart non-FFI-specific finalizers: #45455.
dcharkes commentedon May 26, 2021
Given that C finalizers are available, and Dart finalizers are tracked in #45455, I'm going to lock this issue for now.
If you have questions about how to use the finalizers in C, please post your questions on StackOverflow.
If you want to chime in on the Dart finalizer design discussion, please post in #45455.
If for whatever reason #45455 does not come to be, I'll unlock this discussion again.
vsmenon commentedon Oct 31, 2022
@dcharkes - are we ready to close this issue now?
dcharkes commentedon Oct 31, 2022
Yes!
Available in https://api.dart.dev/stable/2.18.3/dart-ffi/NativeFinalizer-class.html.