在 JNI 函数中,当我就地更改从 Java 代码传递的数组时,数组不会修改
In JNI function when I change an Array in-place that was passed from Java code the Array doesn't modify
我正在将一个 int 数组从 Java 传递到本机方法。
然后在 JNI 函数中,我使用 GetIntArrayElements() 创建了一个指向 int 数组的指针,并作为 *isCopy 参数 JNI_FALSE 传递。我认为这不会创建原始数组的副本,我可以就地修改数组。然后我使用 ReleaseIntArrayElements() 并作为模式参数 JNI_ABORT 传递以仅释放缓冲区。但这没有用。
来自 JNI 文档:
- 模式 0:复制回内容并释放元素缓冲区
- 模式JNI_COMMIT:复制回内容但不释放元素缓冲区
- 模式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;
}
您似乎误解了 GetIntArrayElements
的 isCopy
参数的用途。它不是一个输入参数,告诉 GetIntArrayElements
是否应该给你一个数组数据的副本;它是一个输出参数,GetIntArrayElements
可以用来告诉 你 它是否创建了副本。
来自文档:
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
因此,如果您传递了一个非 NULL jboolean*
,您可以稍后检查该值。如果您传递 NULL
,您将不会获得此信息。例如,如果您只打算从数据中 读取 ,那么知道它是否是一个副本可能就没有意义了,因为您可能只是要使用 JNI_ABORT
释放元素时。
您误用了 jboolean *isCopy
。这是一个输出参数,您应该在实际调用 env->GetIntArrayElements(tbl, isCopy);
之后检查。如果是 returns JNI_FALSE
则不会复制。
这是必要的,因为 GC 可以不可预测地 将元素从一个位置移动到另一个位置,您应该始终将更改复制回原始 java 数组。因为你永远不知道实际 java 数组的内存位置。
如果您不想制作副本,您可能正在寻找该方法的 critical
版本。这是 JNI 文档所说的内容:
These restrictions make it more likely that the native code > will obtain an uncopied version of the array, even if the VM > does not support pinning
这并不意味着只要您持有临界区,JVM 就会禁用垃圾收集,尽管它很可能会这样做。
Emp。我的:
For example, a VM may temporarily disable garbage
collection when the native code is holding a pointer to an
array obtained via GetPrimitiveArrayCritical
我正在将一个 int 数组从 Java 传递到本机方法。 然后在 JNI 函数中,我使用 GetIntArrayElements() 创建了一个指向 int 数组的指针,并作为 *isCopy 参数 JNI_FALSE 传递。我认为这不会创建原始数组的副本,我可以就地修改数组。然后我使用 ReleaseIntArrayElements() 并作为模式参数 JNI_ABORT 传递以仅释放缓冲区。但这没有用。
来自 JNI 文档:
- 模式 0:复制回内容并释放元素缓冲区
- 模式JNI_COMMIT:复制回内容但不释放元素缓冲区
- 模式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;
}
您似乎误解了 GetIntArrayElements
的 isCopy
参数的用途。它不是一个输入参数,告诉 GetIntArrayElements
是否应该给你一个数组数据的副本;它是一个输出参数,GetIntArrayElements
可以用来告诉 你 它是否创建了副本。
来自文档:
If isCopy is not NULL, then *isCopy is set to JNI_TRUE if a copy is made; or it is set to JNI_FALSE if no copy is made.
因此,如果您传递了一个非 NULL jboolean*
,您可以稍后检查该值。如果您传递 NULL
,您将不会获得此信息。例如,如果您只打算从数据中 读取 ,那么知道它是否是一个副本可能就没有意义了,因为您可能只是要使用 JNI_ABORT
释放元素时。
您误用了 jboolean *isCopy
。这是一个输出参数,您应该在实际调用 env->GetIntArrayElements(tbl, isCopy);
之后检查。如果是 returns JNI_FALSE
则不会复制。
这是必要的,因为 GC 可以不可预测地 将元素从一个位置移动到另一个位置,您应该始终将更改复制回原始 java 数组。因为你永远不知道实际 java 数组的内存位置。
如果您不想制作副本,您可能正在寻找该方法的 critical
版本。这是 JNI 文档所说的内容:
These restrictions make it more likely that the native code > will obtain an uncopied version of the array, even if the VM > does not support pinning
这并不意味着只要您持有临界区,JVM 就会禁用垃圾收集,尽管它很可能会这样做。
Emp。我的:
For example, a VM may temporarily disable garbage collection when the native code is holding a pointer to an array obtained via
GetPrimitiveArrayCritical