NDK开发之JNI的异常处理与缓存策略

在使用JNI的时候,可能会产生异常,此时就需要对异常进行处理

异常处理

JNI抛出Throwable异常,在Java层可以用Throwable捕捉
而在C只有清空异常这种处理
但如果在JNI中通过ThrowNew抛出异常,则在Java曾可以捕获
例子(在native访问不存在的属性)
Java中声明native方法

1
public native void exception();

在native中进行处理

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
JNIEXPORT void JNICALL Java_com_cj5785_jni_JniTest_exception
(JNIEnv *env, jobject jobj)
{
jclass cls = (*env)->GetObjectClass(env, jobj);
jfieldID fid = (*env)->GetFieldID(env, cls, "key0", "Ljava/lang/String;");
//检测是否发生Java异常
jthrowable exception = (*env)->ExceptionOccurred(env);
if (exception != NULL)
{
//清空异常信息
(*env)->ExceptionClear(env);
//抛出异常给Java层
jclass exception_cls = (*env)->FindClass(env, "java/lang/IllegalArgumentException");
(*env)->ThrowNew(env, exception_cls, "key0 is not invalid");
}
}

此处访问了一个不存在的属性,通过ThrowNew将异常抛给Java处理
有时候需要在native中添加补救措施,这取决于实际的运用场景

因此在异常处理的时候,要保证Java能够正常运行

缓存策略

在多次获取同一个属性或对象的时候,使用缓存,可以有效减少属性和对象的内存占用

在使用的时候定义

定义一个static变量,保证其生成的只有一个,这样就节省了内存
局部static的生命周期随着程序而存在,作用于在其定义的代码块内

1
2
3
4
5
6
7
8
9
10
11
JNIEXPORT void JNICALL Java_com_cj5785_jni_JniTest_cached
(JNIEnv *env, jobject jobj)
{
jclass cls = (*env)->GetObjectClass(env, jobj);
//设置局部静态变量,保证其只会被赋值一次
static jfieldID key_id = NULL;
if (key_id == NULL)
{
key_id = (*env)->GetFieldID(env, cls, "key", "Ljava/lang/String;");
}
}

初始化时候定义

初始化全局变量,动态库加载完成之后,立刻存储起来
那么在调用的时候就需要在加载完成立即调用

1
2
3
4
5
6
static {
System.loadLibrary("JNITest");
initIds();
}

public native static void initIds();

在native中定义全局,然后对其进行赋值

1
2
3
4
5
6
7
8
jfieldID key_fid;
jmethodID random_mid;
JNIEXPORT void JNICALL Java_com_cj5785_jni_JniTest_initIds
(JNIEnv *env, jclass jcls)
{
key_fid = (*env)->GetFieldID(env, jcls, "key", "Ljava/lang/String;");
random_mid = (*env)->GetMethodID(env, jcls, "getRandomInt", "(I)I");
}

Donate comment here