Skip to content
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

In jnigen, Java objects seem to be auto managed by Dart heap, is it allowed, or shall we call dispose manually for each object? #848

Closed
fzyzcjy opened this issue Dec 5, 2023 · 5 comments

Comments

@fzyzcjy
Copy link

fzyzcjy commented Dec 5, 2023

Cross-post from dart-lang/sdk#54233, since if we should not do this, the jnigen may need some refactor. (I hope we are allowed to do such auto management!)

@HosseinYousefi
Copy link
Member

By default Java objects (classes extending JObject) are attached to a NativeFinalizer, so once they're unreachable and GC runs, DeleteGlobalRef is called.

Alternatively you can delete the global reference manually by calling .release():

final o = someJObject();
// do stuff with o
o.release();

or using an Arena:

using((arena) {
  final o = someJObject()..releasedBy(arena);
});
// o is released here.

release internally detaches the native finalizer, and calls the DeleteGlobalRef immediately.

This doesn't mean that the object is completely GC'd though. Only this one global reference to the object is released. Once the object is unreachable completely (no references in either Java or global references in Dart), JVM will eventually GC it.

@fzyzcjy
Copy link
Author

fzyzcjy commented Dec 5, 2023

Thank you for the info, I know it is done by native finalizer, and my main worry was described in dart-lang/sdk#54233.

@HosseinYousefi
Copy link
Member

Thank you for the info, I know it is done by native finalizer, and my main worry was described in dart-lang/sdk#54233.

JNIgen solves this by giving the option of manually releasing the references to the user. Small number of small objects? Fine to let it be cleaned up by the GC. Large number of objects? Maybe use an arena to explicitly clean up the references (and still rely on JVM to clean up the object in its own GC cycle – since there isn't really an explicit dispose in Java).

Java is also different from Rust with the memory ownership rules and not having a GC. So the exact same approach might not be applicable to your package.

@dcharkes
Copy link
Collaborator

dcharkes commented Dec 5, 2023

Java is also different from Rust with the memory ownership rules and not having a GC. So the exact same approach might not be applicable to your package.

+1 #849 (comment)

JNIgen solves this by giving the option of manually releasing the references to the user. Small number of small objects? Fine to let it be cleaned up by the GC. Large number of objects? Maybe use an arena to explicitly clean up the references (and still rely on JVM to clean up the object in its own GC cycle – since there isn't really an explicit dispose in Java).

If users of JNIgen are in a context where there is already a dispose cycle (e.g. some Flutter code), you can hook into that.

Organizing flutter_rust_bridge in the same way (e.g. attaching a native finalizer, and cancelling the native finalizer on a manual dispose call) gives your users the option based on usage pattern.

@fzyzcjy
Copy link
Author

fzyzcjy commented Dec 5, 2023

@HosseinYousefi @dcharkes Thank you for the replies!

Organizing flutter_rust_bridge in the same way (e.g. attaching a native finalizer, and cancelling the native finalizer on a manual dispose call)

Yes that's both what V1 and V2 do (though V1's doc is suboptimal after I learn all these discussions today ;) ).

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

3 participants