NDK-JNI的一些实践推荐

/ 0评 / 0

回收本地引用

我们在使用jni的时候,除了要遵循原生的内存管理规范,比如new出来的对象需要delete掉,还要额外对于jni的对象进行回收处理。

不需要回收的类型:jboolean、 jchar 、jint等基础数据类型

需要回收的类型:全局引用、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 ,jmethodID等引用类型

(*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

https://www.ibm.com/developerworks/cn/java/j-lo-jnileak/

https://www.kancloud.cn/owenoranba/jni/120442

发表评论

您的电子邮箱地址不会被公开。