回收本地引用
我们在使用jni的时候,除了要遵循原生的内存管理规范,比如new出来的对象需要delete掉,还要额外对于jni的对象进行回收处理。
不需要回收的类型:jboolean、 jchar 、jint等基础数据类型
不能会收的类型:jfieldID、jmethodID,不然会报错
需要回收的类型:全局引用、jobject以及其子类jclass、jstring、jarray等
释放方法
1、jstring & char *
// 创建 jstring 和 char*
jstring jstr = (jniEnv)->CallObjectMethod(jniEnv, mPerson, getName);
char cstr = (char) (jniEnv)->GetStringUTFChars(jniEnv,jstr, 0);
// 释放
(jniEnv)->ReleaseStringUTFChars(jniEnv, jstr, cstr);
(jniEnv)->DeleteLocalRef(jniEnv, jstr);
2、 jobject,jobjectArray,jclass等引用类型
(*jniEnv)->DeleteLocalRef(jniEnv, XXX);
3、jbyteArray
jbyteArray audioArray = jnienv->NewByteArray(frameSize);
jnienv->DeleteLocalRef(audioArray);
4、GetByteArrayElements
jbyte* array= (*env)->GetByteArrayElements(env,jarray,&isCopy);
(*env)->ReleaseByteArrayElements(env,jarray,array,0);
5、NewGlobalRef
jobject ref= env->NewGlobalRef(customObj);
env->DeleteGlobalRef(customObj);
缓存MethodID以及FieldID
我们在调用java方法的时候都是通过jni去间接调用,每一次都需要FindClass、GetMethodID、GetFieldID,但是jni操作其实是很耗费性能的,所以我们可以直接将MethodID、FieldID给缓存起来,这样就可以提高效率。
1、在使用时缓存
C中的static变量可以只初始化一次,然后在程序运行期间一直存在,所以我们可以使用static局部变量来在使用时缓存
static jmethodID id = null;
if(id == null){
id = env->GetMethonID(//)
if(id == null){
return
}
}
2、在类加载的时候缓存
可以看到,我们在java的static方法中主动进行调用去缓存ID
//java
class Test{
static{
System.loadLibrary(///)
initIds();
}
private static native void initIds();
}
//native
jmethodID id;
void initIds(){
id = ////GetMethonID()
}
两种方式的区别
比起在类加载时进行缓存,使用时缓存有如下缺点
1、使用时缓存,每次都得判断是否为null
2、方法id和字段id在类被unload的时候就会失效,如果类被unload了再load,那么缓存的id就不对了
为什么不能缓存jclass
jclass是jobject的子类,当我们在native方法中使用FindClass或者GetObjectClass获取jclass的时候,获取到的只是一个局部引用,当方法结束以后,局部引用会被系统回收,当我们再次调用的时候,就会让程序崩溃。
更多关于局部引用的详解请参看:https://www.ibm.com/developerworks/cn/java/j-lo-jnileak/
参数传递最好使用基础类型
我们可以看到,sumValues2是传递的object,我们想获取其字段,需要使用jni操作,所以如果不是非必要,我们可以在java层就将字段拆解传递
int sumValues(JNIEnv* env, jobject obj, jint a, jint b,jint c, jint d, jint e, jint f){
return a + b + c + d + e + f;
}
int sumValues2(JNIEnv* env, jobject obj, jobject allValues){
jint avalue = (*env)->GetIntField(env, allValues, a);
jint bvalue = (*env)->GetIntField(env, allValues, b);
jint cvalue = (*env)->GetIntField(env, allValues, c);
jint dvalue = (*env)->GetIntField(env, allValues, d);
jint evalue = (*env)->GetIntField(env, allValues, e);
jint fvalue = (*env)->GetIntField(env, allValues, f);
return avalue + bvalue + cvalue + dvalue + evalue + fvalue;
}
https://blog.csdn.net/c1481118216/article/details/77727573