Previous | Next | Trail Map | Using the JNI | Java Native Interface Programming

Local and Global References

So far, we have used data types such as jobject, jclass, and jstring to denote references to Java programming language objects. However, the JNI creates references for all object arguments passed in to native methods, as well as all objects returned from JNI functions.

References serve to keep the Java programming language objects from being garbage collected. By default, the JNI creates local references because local references ensure that the Virtual Machine can eventually free the Java programming language objects. Local references become invalid when program execution returns from the native method in which the local reference is created. Therefore, a native method must not store away a local reference and expect to reuse it in subsequent invocations.

For example, the following program, which is a variation of the native method in FieldAccess.c, mistakenly caches the Java programming language class for the field ID so that it does not have to repeatedly search for the field ID based on the field name and signature at each invocation:

/* This code is illegal */
static jclass cls = 0;
static jfieldID fld;

JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
  ...
  if (cls == 0) {
    cls = (*env)->GetObjectClass(env, obj);
    if (cls == 0)
      ... /* error */
    fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
  }
  ... /* access the field using cls and fid */
}
This program is illegal because the local reference returned from GetObjectClass is only valid before the native method returns. When the Java application calls the native method Java_FieldAccess_accessField a second time, the native method tries to use an invalid local reference. This leads to either the wrong results or to a VM crash.

You can overcome this problem by creating a global reference. A global reference will remain valid until it is explicitly freed. The following code rewrites the previous program and correctly uses a global reference to cache the class for the field ID:

/* This code is OK */
static jclass cls = 0;
static jfieldID fld;

JNIEXPORT void JNICALL
Java_FieldAccess_accessFields(JNIEnv *env, jobject obj)
{
  ...
  if (cls == 0) {
    jclass cls1 = (*env)->GetObjectClass(env, obj);
    if (cls1 == 0)
      ... /* error */
    cls = (*env)->NewGlobalRef(env, cls1);
    if (cls == 0)
      ... /* error */      
    fid = (*env)->GetStaticFieldID(env, cls, "si", "I");
  }
  ... /* access the field using cls and fid */
}

A global reference keeps the Virtual Machine from unloading the Java programming language class, and therefore also ensures that the field ID remains valid, as discussed in Accessing Java Fields. However, the native code must call DeleteGlobalRefs when it no longer needs access to the global reference. Otherwise, the Virtual Machine will never unload the corresponding Java programming language object, the Java class referenced by cls above.

In most cases, the native programmer should rely on the VM to free all local references after the native method returns. In certain situations, however, the native code may need to call the DeleteLocalRef function to explicitly delete a local reference. These situations are:


Previous | Next | Trail Map | Using the JNI | Java Native Interface Programming