如何在JNI中读取bytearray?

时间:2011-07-18 04:25:37

标签: java-native-interface bytearray pass-by-reference

是否可以在JNI中引用整个bytearray但不调用任何副本?

在本机C代码中,我有一个从Java传递的bytearray,我只是想将一些数据与这个bytearray进行比较,所以我不想做任何内存复制。有可能吗?

我知道我可以通过使用类似的GetPrimitiveArrayCritical来获取本地的bytearray指针

JNIEXPORT jbyteArray JNICALL Java_nfore_android_bt_pro_nfhfp_dsp
(JNIEnv *env, jobject jobj, jbyteArray jbIn, jbyteArray jbBase){

    jbyte *bufferIn;
    jbyte *bufferBase;
    bufferIn = (*env)->GetPrimitiveArrayCritical(env, jbIn, NULL);

    LOGD("Begin of dsp()"); 
    LOGD("In dsp() Before Comparing...");

        // Compare bufferIn with bufferBase here...

    LOGD("In dsp() After Comparing...");
    LOGD("End of dsp()");

    (*env)->ReleasePrimitiveArrayCritical(env, jbIn, bufferIn, 0);

    return jbIn;
}

正如您所看到的,因为我可能会更改jbIn中的数据,所以我应该使用GetPrimitiveArrayCritical获取其指针并稍后释放它。

但是,如果我只想读取bytearray jbBase,我怎么能得到jbBase的指针但不能使用GetPrimitiveArrayCritical?

任何建议都将不胜感激。非常感谢。

2 个答案:

答案 0 :(得分:9)

我使用以下内容来读取字节数组......

jbyte *b = (jbyte *)env->GetByteArrayElements(jbBase, NULL);
// read bytes in *b here
...
// release it
env->ReleaseByteArrayElements(jbBase, b, 0 );

你还需要释放它,因为它会阻止垃圾收集器在你还在使用它的时候摆脱它。

答案 1 :(得分:6)

GetByteArrayElements方法无法保证您的程序使用引用或复制。 JNI返回isCopy标志,表示它复制了对象或固定它(pin表示引用)。如果你不想永远复制它,你不必使用GetArrayElements方法,因为它总是返回副本(JVM决定是否复制,可能是复制首选,因为复制减轻了垃圾收集器的负担)。我试过了,看到我的ram在发送一个大阵列时增加了。您还可以在以下链接中看到:

IBM copy and pin(从树状视图查看副本和图钉主题)

正如文档所述,GetPrimitiveArrayCritical返回Java数组的直接堆地址,禁用垃圾收集,直到调用相应的ReleasePrimitiveArrayCritical。所以你必须使用GetPrimitiveArrayCritical,如果你不想复制(当你有一个大数组时需要它)。如果我们查看你的代码,你可以按如下所示逐个获取数组(我假设你将int数组作为一个jobject发送到JNI函数):

length = (*env)->GetArrayLength(jbIn);
bufferIn = (*env)->GetPrimitiveArrayCritical(env, jbIn, NULL);
for(int i=0; i<length; i++)
   printf("Value of jbIn[%d]: %d", i, bufferIn[i]);
(*env)->ReleasePrimitiveArrayCritical(env, jbIn, bufferIn, 0);

重要说明:GetPrimitiveArrayCritical之后不能使用GetArrayLength,因为JNI不允许程序在get critical和release方法之间为同一个对象调用任何JNI函数。