The Java TM Tutorial

| Start of Tutorial > Start of Trail > Start of Lesson | Search

Trail: Java Native Interface
Lesson: Interacting with Java from the Native Side

## Local and Global References

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

> References serve to keep the Java objects from being garbage collected. By default, the JNI creates local references because local references ensure that the Java Virtual Machine can eventually free the Java 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 class for the member variable ID so that it does not have to repeatedly search for the member variable ID based on the member variable 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 member variable using cls and fid */
> >         ...
> >     }

> This program is illegal because the local reference returned from `GetObjectClass` is valid only until the native method returns. When the Java application calls the native method `Java_FieldAccess_accessFields` 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 remains 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 member variable ID:

> >     /* This code is correct. */
> >     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 member variable using cls and fid */
> >         ...
> >     }

> A global reference keeps the Java Virtual Machine from unloading the Java class, and therefore also ensures that the member variable ID remains valid, as discussed in Accessing Java Member Variables. However, the native code must call `DeleteGlobalRef` when it no longer needs access to the global reference. Otherwise, the Java Virtual Machine will never unload the corresponding Java object, the Java class referenced by `cls` above.

> In most cases, the native programmer should rely on the Java Virtual Machine 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:

> - You may know that you are holding the only reference to a large Java object and you do not want to wait until the current native method returns before the garbage collector can reclaim the object. For example, in the following program segment, the garbage collector may be able to free the Java object referred to by `lref` when it is running inside `lengthyComputation`:

>   >         ...
>   >         lref = ...            /* a large Java object */
>   >         ...                   /* last use of lref */
>   >         (*env)->DeleteLocalRef(env, lref);
>   >         lengthyComputation(); /* may take some time */
>   >         return;               /* all local refs will now be freed */
>   >     }

> - You may need to create a large number of local references in a single native method invocation. This may result in an overflow of the internal JNI local reference table. It is a good idea to delete those local references that will not be needed. For example, in the following program segment, the native code iterates through a potentially large array `arr` consisting of Java strings. After each iteration, the program can free the local reference to the string element:

>   >         ...
>   >         for(i = 0; i < len; i++) {
>   >             jstring jstr = (*env)->GetObjectArrayElement(env, arr, i);
>   >             ...                                /* processes jstr */
>   >             (*env)->DeleteLocalRef(env, jstr); /* no longer needs jstr */
>   >         }
>   >         ...

| Start of Tutorial > Start of Trail > Start of Lesson | Search