引用类型:局部引用和全局引用
作用:在JNI中告知虚拟机何时回收一个JNI变量
局部引用
局部引用,通过NewLocalRef创建局部引用对象,DeleteLocalRef手动释放对象
1.访问一个很大的java对象,使用完之后,还要进行复杂的耗时操作
2.创建了大量的局部引用,占用了太多的内存,而且这些局部引用跟后面的操作没有关联性
全局引用
共享(可以跨多个线程),手动控制内存使用
全局引用,通过NewGlobalRef创建局部引用对象,通过DeleteGlobalRef手动释放对象
弱全局引用
节省内存,在内存不足时可以是释放所引用的对象
创建:NewWeakGlobalRef,销毁:DeleteGlobalWeakRef
可以引用一个不常用的对象,如果为NULL,临时创建
异常处理
1.保证Java代码可以运行
2.补救措施保证C代码继续运行
JNI自己抛出的异常,在Java层通过Throwable可以捕获
用户通过ThrowNew抛出的异常,可以在Java层捕捉
JNIEXPORT void JNICALL Java_com_ccg_jni_JniTest_exeception(JNIEnv *env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, cls, "key2", "Ljava/lang/String;");
//检测是否发生Java异常
jthrowable exception = (*env)->ExceptionOccurred(env);
if (exception != NULL){
//让Java代码可以继续运行
//清空异常信息
(*env)->ExceptionClear(env);
//补救措施
fid = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
}
//获取属性的值
jstring jstr = (*env)->GetObjectField(env, jobj, fid);
char *str = (*env)->GetStringUTFChars(env, jstr, NULL);
//对比属性值是否合法
if (_stricmp(str, "super jason") != 0){
//认为抛出异常,给Java层处理,java后面的代码可以继续执行
jclass newExcCls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env,newExcCls,"key's value is invalid!");
}
}
缓存策略
static
//static jfieldID key_id
JNIEXPORT void JNICALL Java_com_ccg_jni_JniTest_cached(JNIEnv *env, jobject jobj){
jclass cls = (*env)->GetObjectClass(env, jobj);
//获取jfieldID只获取一次,生命周期是第一次执行这个方法时创建,结束时停止,但是值会被缓存起来
//局部静态变量
static jfieldID key_id = NULL;
if (key_id == NULL){
key_id = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
printf("--------GetFieldID-------\n");
}
}
初始化全局变量,动态库加载完成之后,立刻缓存起来
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_ccg_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");
}