JNI 引用变量
引用类型:局部引用和全局引用
作用:在JNI中告知虚拟机何时回收一个JNI变量
局部引用
//局部引用
public native void localRef();
使用
//局部引用:
//通过DeleteLocalRef手动释放对象
//1.访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作
//2.创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性
//这个时候都需要通过DeleteLocalRef手动释放掉对象
JNIEXPORT void JNICALL Java_com_gxl_JniTest_localRef
(JNIEnv *env, jobject jobj){
for (int i = 0; i < 100; i++){
//获取Date的class
jclass cls=(*env)->FindClass(env, "java/util/Date");
//获取Date的构造方法的id
jmethodID cons_id=(*env)->GetMethodID(env, cls, "<init>", "()V");
//创建Date对象
jobject date=(*env)->NewObject(env, cls, cons_id);
//。。。。。中间一些列操作
//在操作完成后要进行释放,否则每次循环都会产生一个Date对象
//不在使用jobject对象了
//通知垃圾回收器回收这些对象
(*env)->DeleteLocalRef(env,date);
}
}
全局引用
//全局变量
//创建全局变量
public native void createGlobalRef();
//获取全局变量
public native String getGlobalRef();
//删除全局变量
public native void deleteGlobalRef();
使用
t.createGlobalRef();
String globalRef=t.getGlobalRef();
System.out.println("全局变量:"+globalRef);
t.deleteGlobalRef();
函数实现
//全局引用
//共享(可以跨多个线程),手动控制内存使用
jstring global_str;
//创建全局引用
JNIEXPORT void JNICALL Java_com_gxl_JniTest_createGlobalRef
(JNIEnv *env, jobject jobj){
//这句话是乱码的,要想解决这个乱码看上次的string
jstring str=(*env)->NewStringUTF(env, "c 的全局引用");
global_str=(*env)->NewGlobalRef(env, str);
}
//获取全局引用
JNIEXPORT jstring JNICALL Java_com_gxl_JniTest_getGlobalRef
(JNIEnv *env, jobject jobj){
return global_str;
}
//释放全局引用
JNIEXPORT void JNICALL Java_com_gxl_JniTest_deleteGlobalRef
(JNIEnv *env, jobject jobj){
(*env)->DeleteGlobalRef(env,global_str);
}
弱全局引用
节省内存,在内存不足时可以是释放所引用的对象
可以引用一个不常用的对象,如果为NULL,临时创建
创建:NewWeakGlobalRef,销毁:DeleteGlobalWeakRef
异常
//异常
public String key="json";
public native void exception();
使用
try{
//如果c中发生异常,会在这里直接崩溃,后面的不会运行
t.exception();
}catch(Throwable e){
//如果在c中发生异常通过Throwable可以捕捉到
System.out.println("发生异常:"+e.getMessage());
}
System.out.println("发生异常之后");
函数实现
//异常处理
//1.保证Java代码可以运行
//2.补救措施保证C代码继续运行
//JNI自己抛出的异常,在Java层可以通过Throwable被捕捉,也可以在C层清空
//用户通过ThrowNew抛出的异常,可以在Java层捕捉
JNIEXPORT void JNICALL Java_com_gxl_JniTest_exception
(JNIEnv *env, jobject jobj){
jclass cls=(*env)->GetObjectClass(env, jobj);
//获取key2 获取不到会发生异常
jfieldID fid=(*env)->GetFieldID(env, cls, "key2", "Ljava/lang/String;");
//检测是否发生异常
jthrowable throw=(*env)->ExceptionOccurred(env);
if (throw != NULL){
//如果有异常
//让java代码可以继续运行
//清楚异常
(*env)->ExceptionClear(env);
//补救措施
fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
}
//获取key属性的值
jstring value=(*env)->GetObjectField(env, jobj, fid);
//将jstring 转成 char*
char* c_value=(*env)->GetStringUTFChars(env, value, NULL);
//判断key的值是不是 super json
if (_stricmp(c_value, "super json") != 0){
//将异常抛给java层去处理
//找到异常类
jclass excep=(*env)->FindClass(env, "java/lang/IllegalArgumentException");
//抛出异常
(*env)->ThrowNew(env, excep, "value is invalidate");
}
}
缓存策略
这里的缓存是通过静态局部变量来实现的
//缓存策略
public native void cache();
使用
for(int i=0;i<100;i++){
t.cache();
}
函数实现
//使用静态局部变量来缓存
JNIEXPORT void JNICALL Java_com_gxl_JniTest_cache
(JNIEnv * env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
//静态局部变量,每一次这次方法调用都会存在,在这个方法中是共享的。
//这里使用static 局部变量无论调用多少次这个方法则只会打印一次
static jfieldID key_id=NULL;
//如果使用的是局部变量,调用多少次这个方法就会打印多少次
//fieldID key_id = NULL;
if (key_id == NULL){
key_id = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
printf("--------GetFieldID-------\n");
}
}
全局变量
public native static void initIds();
使用
static{
System.loadLibrary("jni_04");
initId();
}
函数实现
//初始化全局变量,动态库加载完成之后,立刻缓存起来
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_dongnaoedu_jni_JniTest_initIds(JNIEnv *env, jclass jcls){
key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
random_mid = (*env)->GetMethodID(env, jcls, "genRandomInt", "(I)I");
}