Understanding the IBM SDK for Java > Understanding the Java Native Interface (JNI) > | | |
The JNI and the Garbage CollectorFor general information about the IBM Garbage Collector, see Understanding the Garbage Collector. |To collect unreachable objects, the Garbage Collector must know when Java |objects are referenced by native code. The JNI implementation uses "root |sets" to ensure that objects can be reached. A root set is a set of direct |(usually relocatable) object references that are traceable by the GC. |There are several types of root set. The union of all root sets provides |the starting set of objects for a GC mark phase. Beginning with this starting |set, the GC traverses the entire object reference graph. Anything that remains |unmarked is unreachable garbage. (This description is an over-simplification |when f-reachability and weak references are considered. See Detailed description of garbage collection and |the JVM specification.) | |Overview of JNI object references|The implementation details of how the GC finds a JNI object reference are |not detailed in the JNI specification. Instead, the JNI specifies a required |behavior that is both reliable and predictable. | |Local and global references|Local references are "automatic" references that are scoped to |their creating stack frame and thread, and automatically deleted when their |creating frame returns. Global references allow native code to "promote" |a local reference into a form usable by native code in any thread attached |to the JVM. | |Global references and memory leaks|Global references are not automatically deleted, so their use places a |burden of memory management on the programmer; every global reference establishes |a root for the referent and makes its entire subtree reachable. Every "create |global reference" call must have a corresponding "free global reference" call |to prevent memory leaks. |Leaks in global references eventually lead to an out-of-memory error. These |errors can be quite difficult to solve, especially if you do not perform JNI |exception handling. See Handling exceptions. |To provide JNI global reference capabilities and still provide some automatic |garbage collection of the referents, the JNI provides two functions (NewWeakGlobalRef |and DeleteWeakGlobalRef) that provide JNI access to Java's weak references. | For information and important warnings about the use of JNI global weak references, |see the JNI specification. | |Local references and memory leaks|The automatic garbage collection of out-of-scope local references |prevents memory leaks in most situations. This automatic garbage collection |occurs when a native thread returns to Java (native methods) or detaches from |the JVM (Invocation API). Local reference memory leaks are possible if automatic |garbage collection does not occur; for example, if a native method does not |return to the JVM, or if a program that uses the Invocation API does not detach |from the JVM. |Consider the code in the following example, where native code creates new |local references in a loop: |while ( <condition> ) |{ | jobject myObj = (*env)->NewObject( env, clz, mid, NULL ); | | if ( NULL != myObj ) | { | /* we know myObj is a valid local ref, so use it */ | jclass myClazz = (*env)->GetObjectClass(env, myObj); | | /* uses of myObj and myClazz, etc. but no new local refs */ | | /* Without the following calls, we would leak */ | (*env)->DeleteLocalRef( env, myObj ); | (*env)->DeleteLocalRef( env, myClazz ); | } | |} /* end while */| Although new local references overwrite the myObj and myClazz variables |inside the loop, every local reference is kept in the root set until it is |explicitly removed by the DeleteLocalRef call. Without the DeleteLocalRef |calls, the local references would be leaked until the thread returned to Java |or detached from the JVM. | |JNI weak global references|Weak global references are a special kind of global reference. They can |be used in any thread and can be used between native function calls, but do |not act as garbage collector roots. The Garbage Collector disposes of an object |that is referred to by a weak global reference at any time if the object does |not have a strong reference elsewhere. |Because of this special property, you must use weak global references with |caution. If the object referred to by a weak global reference is garbage collected, |the reference becomes a null reference. A null reference can only safely be |used with a subset of JNI functions. To test if a weak global reference has |been collected, use the IsSameObject JNI function to compare the weak global |reference to the null value. |It is not safe to call most JNI functions with a weak global reference, |even if you have tested that the reference is not null, because the weak global |reference could become a null reference after it has been tested or even during |the JNI function. Instead, a weak global reference should always be promoted |to a strong reference before it is used. You can promote a weak global reference |using the NewLocalRef or NewGlobalRef JNI functions. |Weak global references use memory and must be freed with the DeleteWeakGlobalRef |JNI function when it is no longer needed. Failure to free weak global references |causes a slow memory leak, eventually leading to out-of-memory |errors. | |JNI reference management|The platform-independent rules for JNI reference management are: |
Notes:
|
JNI transitions|To understand JNI local reference management and the GC, you must understand |the context of a running thread attached to the JVM. Every thread has a runtime |stack that includes a frame for each method call. From a GC perspective, every |stack establishes a thread-specific "root set" including the union |of all JNI local references in the stack. | | |Each method call in a running VM adds (pushes) a frame onto the stack, |just as every return removes (pops) a frame. Each call point in a running |stack can be characterized as one of the following: |
You can only perform an N2J transition in a thread that meets the following |conditions: |
J2J and N2N transitions|Because object references do not change form as part of J2J or N2N transitions, |J2J and N2N transitions do not affect JNI local reference management. |Any section of N2N code that obtains a large number of local references |without promptly returning to Java can needlessly stress a thread's local |reference capacity, unless local references are managed explicitly by the |native method programmer. | |N2J transitions|For native code to call Java code (N2J) in the current thread, the thread |must first be attached to the JVM in the current process. Every N2J call that |passes object references must have obtained them using JNI, and so they are |either valid local or global JNI refs. Any object references returned from |the call are JNI local references. | |J2N calls|The JVM must ensure that objects passed as parameters from Java to the |native method and any new objects created by the native code remain reachable |by the GC. To handle the GC requirements, the JVM allocates a small region |of specialized storage called a "local reference root set". The local |reference root set is created when: |
The JVM initializes the root set created for a J2N transition with a local |reference to the caller's object or class, and a local reference to each |object passed as a parameter to the native method. New local references created |in native code are added to this J2N root set, unless you create a new "local |frame" using the PushLocalFrame JNI function. |The default root set is large enough to contain 16 local references per |J2N transition. The -Xcheckjni command-line option |causes the JVM to monitor JNI usage. When -Xcheckjni is used, the JVM writes a warning message when more than 16 local references |are required at runtime. This output might indicate you should manage local |references more explicitly, using the JNI functions available. These functions |include NewLocalRef, DeleteLocalRef, PushLocalFrame, PopLocalFrame, and EnsureLocalCapacity. | |J2N returns|When native code returns to Java, the associated JNI local reference "root |set", created by the J2N call, is released. If the JNI local reference |was the only reference to an object, the object is no longer reachable and |can be considered for garbage collection. This out-of-scope |triggered garbage collection is the "automatic" aspect of local reference |collection that simplifies memory management for the JNI programmer. |
|