前言
做过Java的朋友都知道,内存管理这一块是完全透明的,new一个类的实例时,只知道创建完这个类的实例后,会返回这个实例的一个引用,然后拿着这个引用去访问它的成员了(属性、方法),完全不用管JVM内部怎么实现的,如何为新建的对象申请内存,使用完之后如何释放内存,只需要知道有个垃圾回收器在处理这些事情就行了,然而,从Java虚拟机创建的对象传到C/C++代码时会产生引用,根据Java的垃圾回收机制,只要有引用存在就不回触发该引用所指向Java对象的垃圾回收;这些引用在JNI 中分为3种:全局引用(Global Reference)、局部引用 (Local Reference)、弱全局引用 (Week Global Reference) since JDK1.2。
原文链接请标明:
本文出自:【的博客】正文
三种引用的区别
1、全局引用
全局引用可以跨方法、跨线程使用,直到被开发者显式释放。类似局部引用,一个全局引用在被释放前保证引用对象不被GC回收。和局部引用不同的是,没有那么多函数能够创建全局引用。能创建全局引用的函数只有 NewGlobalRef。以下例子说明了如何使用一个全局引用。
java native方法:
public native void createGlobalRef(); public native String getGlobalRef(); public native void deleteGlobalRef();
jni实现:
//全局引用//共享(可以跨多个线程),手动控制内存使用jstring global_str;//创建JNIEXPORT void JNICALL Java_com_study_jni_JniTest_createGlobalRef(JNIEnv *env, jobject jobj){ jstring obj = (*env)->NewStringUTF(env, "jni development is powerful!"); global_str = (*env)->NewGlobalRef(env, obj);}//获得JNIEXPORT jstring JNICALL Java_com_study_jni_JniTest_getGlobalRef(JNIEnv *env, jobject jobj){ return global_str;}//释放JNIEXPORT void JNICALL Java_com_study_jni_JniTest_deleteGlobalRef(JNIEnv *env, jobject jobj){ (*env)->DeleteGlobalRef(env, global_str);}
2、局部引用
一个局部引用仅在创建它的native函数及该函数调用的函数中有效。在一个native函数执行期间创建的所有局部引用将在该函数返回时被释放,创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性。
//模拟:循环创建数组JNIEXPORT void JNICALL Java_com_study_jni_JniTest_localRef(JNIEnv *env, jobject jobj){ int i = 0; for (; i < 5; i++){ //创建Date对象 jclass cls = (*env)->FindClass(env, "java/util/Date"); jmethodID constructor_mid = (*env)->GetMethodID(env, cls, "", "()V"); jobject obj = (*env)->NewObject(env, cls, constructor_mid); //此处省略一百行代码... //不在使用jobject对象了 //通知垃圾回收器回收这些对象 //释放局部引用 (*env)->DeleteLocalRef(env, obj); //此处省略一百行代码... }}
上面代码中,省略了和我们无关紧要的代码,通过FindClass返回一个对java.util.Date对象的局部引用。
3、弱全局引用
节省内存,在内存不足时可以是释放所引用的对象,可以引用一个不常用的对象,如果为NULL,临时创建,弱全局引用使用NewGlobalWeakRef创建,使用DeleteGlobalWeakRef释放。下面简称弱引用。与全局引用类似,弱引用可以跨方法、线程使用。但与全局引用很重要不同的一点是,弱引用不会阻止GC回收它引用的对象,所以在使用时需要多加小心,它所引用的对象可能是不存在的或者已经被回收。
1.创建弱全局引用
用NewWeakGlobalRef函数对弱全局引用进行初始化,例如:
jclass weakGlobalclsweakGlobalcls = (*env)->NewWeakGlobalRef(env,localclazz);
2.引用的比较
给定两个引用(不管是全局、局部还是弱全局引用),我们只需要调用IsSameObject来判断它们两个是否指向相同的对象。例如:(*env)->IsSameObject(env, obj1, obj2)
(*env)->IsSameObject(env, obj, NULL) 或者 obj == NULL
来判断obj是否指向一个null对象即可。但需要注意的是,IsSameObject用于弱全局引用与NULL比较时,返回值的意义是不同于局部引用和全局引用的。比如: if(JNI_FALSE == (*env)->IsSameObject(env,weakGlobalcls,NULL)){//TODO 对象未被回收,可以使用}else{//TODO 对象被垃圾回收器回收,不能使用}
以上就是学习这jni 的三种引用的简单使用,相关的知识并没有深入详细的说明!O(∩_∩)O~~