分享

The JNI and the Garbage Collector

 weicat 2010-01-29
Understanding the IBM SDK for Java > Understanding the Java Native Interface (JNI) > | | |

The JNI and the Garbage Collector

For 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:

|
    |
  1. JNI references are valid only in threads attached to a JVM. |
  2. A valid JNI local reference in native code must be obtained: |
      |
    1. As a parameter to the native code |
    2. As the return value from calling a JNI function
    |
  3. A valid JNI global reference must be obtained from another valid JNI reference |(global or local) by calling NewGlobalRef or NewWeakGlobalRef. |
  4. The null value reference is always valid, and can be used in place of |any JNI reference (global or local). |
  5. JNI local references are valid only in the thread that creates them and |remain valid only while their creating frame remains on the stack.
| |
Notes:
|
    |
  1. Overwriting a local or global reference in native storage with a null |value does not remove the reference from the root set. Use the appropriate |Delete*Ref JNI function to remove references from root sets. |
  2. Many JNI functions (such as FindClass and NewObject) return a null value |if there is an exception pending. Comparing the returned value to the null |value for these calls is semantically equivalent to calling the JNI ExceptionCheck |function. See the JNI specification for more details. |
  3. A JNI local reference must never be used after its creating frame returns, |regardless of the circumstances. It is dangerous to store a JNI local reference |in any process static storage. |
| |

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:

|
    |
  • Java to Java (J2J) |
  • Native to Native (N2N) |
  • Java to Native (J2N) |
  • Native to Java (N2J)
|

You can only perform an N2J transition in a thread that meets the following |conditions:

|
    |
  • The process containing the thread must contain a JVM started using the |JNI Invocation API. |
  • The thread must be "attached" to the JVM. |
  • The thread must pass at least one valid local or global object reference |to JNI.
| |

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:

|
    |
  • A thread is first attached to the JVM (the thread's "outermost" |root set) |
  • At each J2N transition
|

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.

Previous Page | Next Page

    本站是提供个人知识管理的网络存储空间,所有内容均由用户发布,不代表本站观点。请注意甄别内容中的联系方式、诱导购买等信息,谨防诈骗。如发现有害或侵权内容,请点击一键举报。
    转藏 分享 献花(0

    0条评论

    发表

    请遵守用户 评论公约

    类似文章 更多