3

When I create a native implementation peer in c++ how can I ensure that native part is also deleted when java object is deleted by JVM? I can add some methods that user of java object has to call explicitly, but I'd like to know if there some hook that I could put to handle when java object is deleted (garbage collected) so that I can automatically delete c++ implementation object as well.

I reviewed JACE it seems that it does that, but I'd need to run PeerEnhancer to patch generated class file (probably that's how it hooks delete? or maybe it needs this patching for something else). However, I'd like to avoid messing with compiled java files, I don't want anything fancy

Pavel P
  • 13,962
  • 11
  • 68
  • 109

2 Answers2

4

Please be aware that by embracing finalizers, you are tickling JVM in the worst possible place. Invoking JNI in finalizer() is like adjusting engine valve timing while driving. While it is technically possible, it is also very easy to end up with leaking JVM or a crash. With even slightest touch of multithreading, you will deadlock/crash at some point for sure. If you say "i don't want anything fancy", i would suggest going with explicitly called methods. Yes requiring certain method order by convention is dirty design, but then JNI is dirty in general.

If a respected JNI library does an undercover class instrumentation instead of simply using finalizers, it perhaps has a reason. Some recommended reading (and that does not even mention JNI!):

http://asserttrue.blogspot.com/2008/11/finalization-is-evil.html

http://elliottback.com/wp/java-memory-leaks-w-finalize-examples/

My suggestion is: yes implement a baseclass with a virtual method detachFromPeer(), set some "detached" flag in it and then in finalizer just check the flag with some warning.

Pavel Zdenek
  • 6,883
  • 1
  • 18
  • 37
  • I'm aware about GC issues. The code will obviously require manual clean up, but at the same time my code wants to know when GC deleted object. – Pavel P Oct 24 '12 at 17:30
  • Well, do you want to know when GC deleted object, or rather when the program code, the algorithm decides that it doesn't need the object anymore? The later is deterministic and manageable. On the contrary, you can't know when GC decides to call finalizer, if ever. – Pavel Zdenek Oct 24 '12 at 19:38
  • Sorry, title of the question is misleading probably. All I wanted to know is how to hook that event when GC actually discards object, not when/why/how. I don't have any intention to rely on that hook, I need it mostly for debugging (for example, to assert that manually cleanup was already performed etc). – Pavel P Oct 24 '12 at 19:45
  • Not the title of the question, the question itself is misleading then. You are explicitly asking for *"when java object is deleted so that I can automatically delete c++ object"*. Which seriously sounds like relying on GC finalizer hook. Anyway i am glad that debugging/asserting manual cleanup is the most you want to do in finalizer. You have saved yourself some serious future pain. – Pavel Zdenek Oct 24 '12 at 19:50
  • There is some FUD here. Finalizers are called on a single thread, so unless they start threads themselves there is certainly no deadlock issue. – user207421 Oct 25 '12 at 07:12
  • Finalizers are indeed called on a separate thread, but whether on a single thread is disputable. [JVM spec is not so convinced](http://docs.oracle.com/javase/specs/jls/se5.0/html/execution.html#12.6.2). Even if so, the whole thing will work only until the coder forgets to be extraordinaly careful and starts "optimizing" the C++ side. One occurence of trying to access some shared resource during C++ disposal, and the very fact that finalizers run from a separate thread will bite you. – Pavel Zdenek Oct 25 '12 at 09:10
2

This is a rare case where you should really use a finalizer, but you should also make your Java class Closeable as well.

user207421
  • 289,834
  • 37
  • 266
  • 440
  • I'm not a Java expert, I'll pass it on to my java buddies :) Is it possible to put that boilerplate code in some baseclass so that all java classes that need native peers would need to inherit from that class that handles automatically that stuff (e.g. calls virtual detachFromPeer() from java destructor/finalizer to make sure that c++ object isn't left dangling for no reason). – Pavel P Oct 24 '12 at 00:32