如何在JNI中读取bytearray?

Boh*_* Lu 5 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;
}
Run Code Online (Sandbox Code Playgroud)

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

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

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

Jim*_*ris 10

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

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

你仍然需要释放它,因为当你还在使用它时,它会阻止垃圾收集器摆脱它.

  • 它不设置独占模式,但如果您只是读取数组,那么并发访问应该没问题.如果可以同时写入,则需要使用互斥锁或同步.我不确定它是否复制,只要我能告诉它只是返回一个指向数组的指针,我用它作为一个高性能的编解码器,我从来没有注意到它复制数组,虽然很难说是否它做了一个副本. (2认同)

Mus*_*mal 7

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

IBM副本和引脚 (从树视图查看副本和引脚主题)

正如文档所述,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);
Run Code Online (Sandbox Code Playgroud)

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