| When invoking `static native` methods from objects that override |
| [`finalize`](https://docs.oracle.com/javase/9/docs/api/java/lang/Object.html#finalize--), |
| the finalizer may run before the native method finishes execution. |
| |
| Consider the following example: |
| |
| ```java |
| public class GameRunner { |
| // Pointer to some native resource, stored as a long |
| private long nativeResourcePtr; |
| |
| // Allocates the native resource that this object "owns" |
| private static native long doNativeInit(); |
| |
| // Releases the native resource |
| private static native void cleanUpNativeResources(long nativeResourcePtr); |
| |
| public GameRunner() { |
| nativeResourcePtr = doNativeInit(); |
| } |
| |
| @Override |
| protected void finalize() { |
| cleanUpNativeResources(nativeResourcePtr); |
| nativeResourcePtr = 0; |
| super.finalize(); |
| } |
| |
| public void run() { |
| GameLibrary.playGame(nativeResourcePtr); // Bug! |
| } |
| } |
| |
| public class GameLibrary { |
| // Plays the game using the native resource |
| public static native void playGame(long nativeResourcePtr); |
| } |
| ``` |
| |
| During the execution of `GameRunner.run`, the call to `playGame` may not hold |
| the `this` reference live, and its finalizer may run, cleaning up the native |
| resources while the native code is still executing. |
| |
| You can fix this by making the `static native` method not `static`, or by |
| changing the `static native` method so that it is passed the enclosing instance |
| and not the `nativeResourcePtr` value directly. |
| |
| If you can use Java 9, the new method |
| [`Reference.reachabilityFence`](https://docs.oracle.com/javase/9/docs/api/java/lang/ref/Reference.html#reachabilityFence-java.lang.Object-) |
| will keep the reference passed in live. Be sure to call it in a finally block: |
| |
| ```java |
| public void run() { |
| try { |
| playAwesomeGame(nativeResourcePtr); |
| } finally { |
| Reference.reachabilityFence(this); |
| } |
| } |
| } |
| ``` |
| |
| Note: This check doesn't currently detect this problem when passing fields from |
| objects other than "this". That is equally unsafe. Consider passing the Java |
| object instead. |
| |
| ## References |
| |
| * [Boehm, "Destructors, finalizers, and synchronization." POPL 2003.](https://www.hpl.hp.com/techreports/2002/HPL-2002-335.html) |
| Section 3.4 discusses this problem. |
| * [Java Language Specification 12.6.2, "Interaction with the Memory Model."](https://docs.oracle.com/javase/specs/jls/se9/html/jls-12.html#jls-12.6.2) |