Local and Global References

Một phần của tài liệu The java™ native interface (Trang 75 - 80)

What are local and global references, and how are they different? We will use a series of examples to illustrate local and global references.

5.1.1 Local References LOCAL AND GLOBAL REFERENCES

5.1.1 Local References

Most JNI functions create local references. For example, the JNI function New- Object creates a new instance and returns a local reference to that instance.

A local reference is valid only within the dynamic context of the native method that creates it, and only within that one invocation of the native method.

All local references created during the execution of a native method will be freed once the native method returns.

You must not write native methods that store a local reference in a static vari- able and expect to use the same reference in subsequent invocations. For example, the following program, which is a modified version of theMyNewStringfunction in Section 4.4.1, uses local references incorrectly.

/* This code is illegal */

jstring

MyNewString(JNIEnv *env, jchar *chars, jint len) {

static jclass stringClass = NULL;

jmethodID cid;

jcharArray elemArr;

jstring result;

if (stringClass == NULL) {

stringClass = (*env)->FindClass(env,

"java/lang/String");

if (stringClass == NULL) {

return NULL; /* exception thrown */

} }

/* It is wrong to use the cached stringClass here, because it may be invalid. */

cid = (*env)->GetMethodID(env, stringClass, "<init>", "([C)V");

...

elemArr = (*env)->NewCharArray(env, len);

...

result = (*env)->NewObject(env, stringClass, cid, elemArr);

(*env)->DeleteLocalRef(env, elemArr);

return result;

}

We have elided the lines that are not directly relevant to our discussion here.

The goal for cachingstringClassin a static variable might have been to elimi- nate the overhead of repeatedly making the following function call:

FindClass(env, "java/lang/String");

LOCAL AND GLOBAL REFERENCES Local References 5.1.1 This is not the right approach becauseFindClassreturns a local reference to the

java.lang.String class object. To see why this is a problem, suppose that the native method implementation ofC.f callsMyNewString:

JNIEXPORT jstring JNICALL

Java_C_f(JNIEnv *env, jobject this) {

char *c_str = ...;

...

return MyNewString(c_str);

}

After the native methodC.f returns, the virtual machine frees all local refer- ences created during the execution of Java_C_f. These freed local references include the local reference to the class object stored in thestringClassvariable.

Future MyNewString calls will then attempt to use an invalid local reference, which could lead to memory corruption or system crashes. A code segment such as the following, for example, makes two consecutive calls to C.f and causes

MyNewString to encounter the invalid local reference:

...

... = C.f(); // The first call is perhaps OK.

... = C.f(); // This would use an invalid local reference.

...

There are two ways to invalidate a local reference. As explained before, the virtual machine automatically frees all local references created during the execu- tion of a native method after the native method returns. In addition, programmers may explicitly manage the lifetime of local references using JNI functions such as

DeleteLocalRef.

Why do you want to delete local references explicitly if the virtual machine automatically frees them after native methods return? A local reference keeps the referenced object from being garbage collected until the local reference is invali- dated. TheDeleteLocalRefcall inMyNewString, for example, allows the inter- mediate array object, elemArr, to be garbage collected immediately. Otherwise the virtual machine will only be able to free theelemArr object after the native method that callsMyNewString (such asC.f above) returns.

A local reference may be passed through multiple native functions before it is destroyed. For example, MyNewString returns the string reference created by

NewObject. It will then be up to the caller ofMyNewStringto determine whether to free the local reference returned by MyNewString. In theJava_C_f example,

C.f in turn returns the result ofMyNewStringas the result of the native method call. After the virtual machine receives the local reference from the Java_C_f

5.1.2 Global References LOCAL AND GLOBAL REFERENCES

function, it passes the underlying string object to the caller of C.f and then destroys the local reference that was originally created by the JNI functionNewOb- ject.

Local references are also only valid in the thread that creates them. A local reference that is created in one thread cannot be used in another thread. It is a pro- gramming error for a native method to store a local reference in a global variable and expect another thread to use the local reference.

5.1.2 Global References

You can use a global reference across multiple invocations of a native method. A global reference can be used across multiple threads and remains valid until it is freed by the programmer. Like a local reference, a global reference ensures that the referenced object will not be garbage collected.

Unlike local references, which are created by most JNI functions, global ref- erences are created by just one JNI function, NewGlobalRef. The following ver- sion of MyNewStringillustrates how to use a global reference. We highlight the differences between the code below and the code that mistakenly cached a local reference in the last section:

/* This code is OK */

jstring

MyNewString(JNIEnv *env, jchar *chars, jint len) {

static jclass stringClass = NULL;

...

if (stringClass == NULL) { jclass localRefCls =

(*env)->FindClass(env, "java/lang/String");

if (localRefCls == NULL) {

return NULL; /* exception thrown */

}

/* Create a global reference */

stringClass = (*env)->NewGlobalRef(env, localRefCls);

/* The local reference is no longer useful */

(*env)->DeleteLocalRef(env, localRefCls);

/* Is the global reference created successfully? */

if (stringClass == NULL) {

return NULL; /* out of memory exception thrown */

} } ...

}

LOCAL AND GLOBAL REFERENCES Weak Global References 5.1.3 The modified version passes the local reference returned fromFindClass to

NewGlobalRef, which creates a global reference to thejava.lang.String class object. We check whether the NewGlobalRef has successfully created string- Class after deleting localRefCls because the local reference localRefCls

needs to be deleted in either case.

5.1.3 Weak Global References

Weak global references are new in Java 2 SDK release 1.2. They are created using

NewGlobalWeakRef and freed using DeleteGlobalWeakRef. Like global refer- ences, weak global references remain valid across native method calls and across different threads. Unlike global references, weak global references do not keep the underlying object from being garbage collected.

TheMyNewStringexample has shown how to cache a global reference to the

java.lang.String class. The MyNewString example could alternatively use a weak global reference to store the cached java.lang.String class. It does not matter whether we use a global reference or a weak global reference because

java.lang.String is a system class and will never be garbage collected.

Weak global references become more useful when a reference cached by the native code must not keep the underlying object from being garbage collected.

Suppose, for example, a native methodmypkg.MyCls.fneeds to cache a reference to the classmypkg.MyCls2. Caching the class in a weak global reference allows themypkg.MyCls2 class to still be unloaded:

JNIEXPORT void JNICALL

Java_mypkg_MyCls_f(JNIEnv *env, jobject self) {

static jclass myCls2 = NULL;

if (myCls2 == NULL) { jclass myCls2Local =

(*env)->FindClass(env, "mypkg/MyCls2");

if (myCls2Local == NULL) {

return; /* can’t find class */

}

myCls2 = NewWeakGlobalRef(env, myCls2Local);

if (myCls2 == NULL) {

return; /* out of memory */

} }

... /* use myCls2 */

}

We assume thatMyClsandMyCls2have the same lifetime. (For example, they may be loaded by the same class loader.) Thus we do not consider the case when

5.1.4 Comparing References LOCAL AND GLOBAL REFERENCES MyCls2is unloaded and later reloaded while MyClsand its native method imple- mentationJava_mypkg_MyClsremain to be in use. If that could happen, we would have to check whether the cached weak reference still points to a live class object or points to a class object that has already been garbage collected. The next sec- tion will explain how to perform such checks on weak global references.

5.1.4 Comparing References

Given two local, global, or weak global references, you can check whether they refer to the same object using theIsSameObject function. For example:

(*env)->IsSameObject(env, obj1, obj2)

returns JNI_TRUE (or 1) if obj1and obj2 refer to the same object, and returns

JNI_FALSE (or0) otherwise.

ANULLreference in JNI refers to thenullobject in the Java virtual machine.

Ifobj is a local or a global reference, you may use either

(*env)->IsSameObject(env, obj, NULL)

or

obj == NULL

to determine ifobj refers to thenull object.

The rules for weak global references are somewhat different.NULLweak refer- ences refer to thenullobject.IsSameObject, however, has special uses for weak global references. You can use IsSameObjectto determine whether a non-NULL

weak global reference still points to a live object. Suppose wobj is a non-NULL

weak global reference. The following call:

(*env)->IsSameObject(env, wobj, NULL)

returnsJNI_TRUEif wobjrefers to an object that has already been collected, and returnsJNI_FALSE ifwobj still refers to a live object.

Một phần của tài liệu The java™ native interface (Trang 75 - 80)

Tải bản đầy đủ (PDF)

(318 trang)