假设我有以下原型的功能:
JNIEXPORT void JNICALL Java_example_SCLASS_cfunc
(JNIEnv *env, jclass caller, jdoubleArray s, jdoubleArray u, jdoubleArray vt)
我想做这样的事情:
{
jdouble* S_native = (*env)->GetDoubleArrayElements(env, s, JNI_FALSE);
jdouble* U_native = (*env)->GetDoubleArrayElements(env, u, JNI_FALSE);
jdouble* VT_native = (*env)->GetDoubleArrayElements(env, vt, JNI_FALSE);
if(!S_native || !U_native || !VT_native){
(*env)->ReleaseDoubleArrayElements(env, s, S_native, 0);
(*env)->ReleaseDoubleArrayElements(env, u, U_native, 0);
(*env)->ReleaseDoubleArrayElements(env, vt, VT_native, 0);
return;
}
/*Now Use the arrays in some way...*/
(*env)->ReleaseDoubleArrayElements(env, s, S_native, 0);
(*env)->ReleaseDoubleArrayElements(env, u, U_native, 0);
(*env)->ReleaseDoubleArrayElements(env, vt, VT_native, 0);
return;
}
但是我不确定我是否可以这样做,因为我在jni文档中读到了 你应该在生成java异常后立即返回, 即(* env) - > GetDoubleArray ...失败。
所以我不确定如果在上一次失败后再次进行GetDoubleArray调用会发生什么。
因此,面对不确定性,我烦恼地将我的代码格式化为:
{
jdouble* S_native;
jdouble* U_native;
jdouble* VT_native;
S_native = (*env)->GetDoubleArrayElements(env, s, JNI_FALSE);
if(!S_native){
return;
}
U_native = (*env)->GetDoubleArrayElements(env, u, JNI_FALSE);
if(!U_native){
(*env)->ReleaseDoubleArrayElements(env, s, S_native, 0);
return;
}
VT_native = (*env)->GetDoubleArrayElements(env, vt, JNI_FALSE);
if(!VT_native){
(*env)->ReleaseDoubleArrayElements(env, s, S_native, 0);
(*env)->ReleaseDoubleArrayElements(env, u, U_native, 0);
return;
}
/*Now Use the arrays in some way...*/
(*env)->ReleaseDoubleArrayElements(env, s, S_native, 0);
(*env)->ReleaseDoubleArrayElements(env, u, U_native, 0);
(*env)->ReleaseDoubleArrayElements(env, vt, VT_native, 0);
return;
}
这是必要的还是我可以先做第一种方式?
答案 0 :(得分:3)
首先仔细阅读Get<TYPE>ArrayElements
函数的文档。它的第三个参数是一个指针,您可以通过该指针从返回的函数中获取其他信息(本机数组是副本)。您的解决方案仅适用于JNI_FALSE等效于NULL。
所以,如果你真的需要,你应该写:
jboolean isCopy;
jdouble* nativeArr = (*env)->GetDoubleArrayElements(env, arr, &isCopy);
然后,您知道您是在复制阵列还是固定阵列上操作。虽然您不需要这些信息,但
jdouble* nativeArr = (*env)->GetDoubleArrayElements(env, arr, NULL);
// check nativeArr != NULL
// operate on array
(*env)->ReleaseDoubleArrayElements(env, arr, nariveArr, 0);
考虑释放资源和错误检查:如果我们从Get<>ArrayElements
收到NULL,这意味着我们 OutOfMemory 并且搞砸了。此错误后应用程序无法运行,因此我不关心已经分配的资源。留待系统清理。
但要使此解决方案正常工作,您需要从代码中提升OutOfMemoryError
!
我在项目中使用宏来清理代码:
#define D_ARR_GET(narray, array) if((narray = (*env)->GetDoubleArrayElements(env, (array), NULL)) == NULL) { sendOutOfMemory(env); return; }
#define D_ARR_FREE(narray, array) ((*env)->ReleaseDoubleArrayElements(env, (array), (narray), 0))
void sendOutOfMemory(JNIEnv* env) {
jclass oomCls = (*env)->FindClass(env, "java_lang_OutOfMemoryError");
jmethodID errInit = (*env)->GetMethodID(env, oomCls, "<init>", "void(V)");
jobject exc = (*env)->NewObject(env, oomCls, errInit);
(*env)->ExceptionClear(env);
(*env)->Throw(env, (jthrowable) exc);
}
void someJNIfunc(JNIEnv* env, jobject arr) {
jdouble* nativeArr; D_ARR_GET(nativeArr, arr);
// use nativeArr
D_ARR_FREE(nativeArr, arr);
}
请记住,env->Throw
并不意味着返回Java,因此您需要自己return
,如果需要,可以通过本机帧堆栈进行传播(可能使用带有例外情况的C ++,使其不再繁琐)更复杂的解决方案)。