我们知道JNI提供了一些实例和数组类型做为不透明的引用供本地代码使用,比如jobject,jarray,jstring等。
JNI中的引用其实分为三种类型:全局引用,局部引用,弱引用。
全局引用和局部引用的区别在于生命周期,当方法返回的时候,局部引用会被自动释放,但是全部引用和弱引用必须手动释放。
局部引用和全局引用会阻止GC,但是弱引用不会。
下面详细讲一下三种引用的区别:
局部引用
局部引用指向的VM内部空间会在本地方法返回的之后被销毁。我们不能尝试通过static来保存一个局部引用。在上一节MyNewString中,通过NewObject方法创建的引用就是局部引用,但是它被返回给Java继续使用了。
局部引用在方法返回时自动销毁,也可以通过DeleteLocalRef在不使用的时候直接销毁。这样会更及时的GC。
我们在方法中通过JNIEnv创建的引用,绝大部分都是局部引用。
全局引用
全局引用可以跨方法和线程进行访问,必须手动释放。
全局引用只能有一个方法创建,那就是NewGlobalRef方法。下面这个版本的MyNewString展示了怎么使用一个全局引用。
jstring MyNewString(JNIEnv *env, jchar chars, jint len){
static jclass strClass = NULL;
...
if(strClass == NULL){
jclass localClass = (*env)->FindClass(env,"java/lang/String");
strClass = (*env)->NewGlobalRef(env, localClass);
...
//局部引用已经不需要了
(*env)->DeleteLocalRef(env.localClass);
if(strClass == null){
return NULL;
}
}
}
全局引用释放的时候只能通过DeleteGlobalRef来释放
弱引用
弱引用不会影响GC,只能通过NewGlobalWeakRef创建,使用DeleteGlobalRef来释放。
弱引用可以跨线程和跨方法使用。我们一般也是通过static关键字来保存弱引用。
三种引用的比较
对于任何一种引用,包括全局引用,局部引用,弱引用,我们都可以通过IsSameObject来判断两个引用是否指向同一个JVM对象(*env)->IsSameObject(env,obj1,obj2).
在JNI中 NULL指向了Java中的null。对于全局和局部引用,(*env)->IsSameObject(env,obj,NULL)和obj==NULL是一样的。
但是在弱引用中含义会有一点变化,当obj是弱引用的时候,(*env)->IsSameObject(env,obj,NULL);代表的是该弱引用所指向的空间是否被回收。










网友评论