在JNI功能当我改变就地数组这是从Java代码的数组不修改传递

问题描述 投票:2回答:2

我传递从Java的int数组给本地方法。然后JNI函数内我创建了一个指针到int与GetIntArrayElements阵列(),并通过作为完成后将* isCopy参数JNI_FALSE。我认为,这不会创建原始数组的一个副本,我可以代替修改阵列。然后我使用ReleaseIntArrayElements(),并通过作为模式参数JNI_ABORT只是relese缓冲器。但是,这并不能正常工作。

从JNI文档:

  • 模式0:复制回内容并释放elems缓冲区
  • 模式JNI_COMMIT:复制回内容但不释放elems缓冲区
  • 模式JNI_ABORT:释放缓冲区但不复制回变化

当我试图使用ReleaseIntArrayElements,完美的工作模式“0”()。但我不明白为什么,因为我没有创建原始阵列和模式的副本“0”被复制回内容。

我想,JNI总是创建原始数组的一个副本。但随后在* GetIntArrayElements isCopy参数()失去其意义。所以,真正有这样的情况?

这是我的JNI函数

extern "C" JNIEXPORT jdouble JNICALL
Java_my_own_package_MainActivity_myFunction(
    JNIEnv *env,
    jobject /* this */, jintArray tbl) {
    jint *tblptr = env->GetIntArrayElements(tbl, JNI_FALSE);
    tblptr[0] = 0; //in-place change
    env->ReleaseIntArrayElements(tb1, tblptr, JNI_ABORT);
    return 0;
}
java arrays android-studio jvm java-native-interface
2个回答
4
投票

你滥用了jboolean *isCopy。这是实际调用env->GetIntArrayElements(tbl, isCopy);后,你应该检查的输出参数。如果返回JNI_FALSE那么,副本将不会作出。

这是必要的,因为GC可以从一个位置不可预测移动元素到另一个,你应该更改回总是复制到原来的Java数组。因为你永远不知道实际的Java数组的存储位置。

如果你不想创建副本你可能寻找方法的critical版本。下面是JNI文档所说的话:

这些限制使得它更可能是本地代码>将获得阵列的未复制版本,即使虚拟机>不支持钉住

这并不意味着,JVM将只要禁用垃圾收集你拿着一个关键部分,虽然它很可能这样做。

EMP。矿:

例如,VM可以暂时禁用在本机代码被保持经由GetPrimitiveArrayCritical获得的指针数组的垃圾收集


3
投票

你似乎误解了isCopyGetIntArrayElements参数的目的。它不是一个输入参数告诉GetIntArrayElements是否应该给你的阵列数据的副本;它是GetIntArrayElements可以用它来告诉你它是否创造了一个副本的输出参数。

从文档:

如果isCopy非空,然后完成后将* isCopy设置为JNI_TRUE,如果一份拷贝;或者它被设置,如果没有副本作出JNI_FALSE。

所以,如果你传递一个非空jboolean*您可以稍后在检查该值。如果你通过NULL你没有得到这个信息。例如,如果你只打算从数据读取,然后知道它是否是一个副本,可能不是因为你可能只是要释放的元素时使用JNI_ABORT很有趣。

© www.soinside.com 2019 - 2024. All rights reserved.