Local and Global References

本文深入探讨了Java本地接口(JNI)中全局引用的概念及其使用场景。通过实例对比了局部引用和全局引用的区别,并强调了在何种情况下应当使用全局引用来避免程序错误或虚拟机崩溃。此外,还讨论了如何正确释放全局引用以防止内存泄漏。
摘要由CSDN通过智能技术生成

转载自:http://journals.ecs.soton.ac.uk/java/tutorial/native1.1/implementing/refs.html

Local and Global References

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

These references will keep the Java objects from being garbage collected. To make sure that Java objects can eventually be freed, the JNI by default createslocal references. Local references become invalid when the 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 (a variation of the native method in FieldAccess.c) mistakenly caches the Java 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:

/* 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  Java_FieldAccess_accessField is entered the second time, an invalid local reference will be used. This leads to wrong results or to a VM crash.

To overcome this problem, you need to create a global reference. This global reference will remain valid until it is explicitly freed:

/* 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 Java class from begin unloaded, and therefore also ensures that the field ID remains valid, as discussed in Accessing Java Fields. The native code must call DeleteGlobalRefs when it no longer needs access to the global reference; otherwise, the corresponding Java object (e.g., the Java class referenced to by cls above) will never be unloaded.

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:

  • 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 Java object can be reclaimed by the garbage collector. 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 local reference to the string element can be freed:
  •   for(i = 0; i < len; i++) {
        jstring jstr = (*env)->GetObjectArrayElement(env, arr, i);
        ...                                /* processes jstr */ 
        (*env)->DeleteLocalRef(env, jstr); /* no longer needs jstr */
      }
    针对第二种情况,有篇文章分析的非常仔细http://www.ibm.com/developerworks/cn/java/j-lo-jnileak/index.html?ca=drs-值得一读
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值