How to read a bytearray in JNI?

2019-05-06 19:38发布

Is it possible to just reference a entire bytearray in JNI but not invoking any copy ?

In native C code, I have a bytearray passing from Java, and I just want to compare some data to this bytearray so I do not want to do any memory copy. Is it possible ?

I know I could get the pointer of a bytearray in native by using GetPrimitiveArrayCritical something like that

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;
}

As you could see, because I might change the data in the jbIn, I should use GetPrimitiveArrayCritical to get its pointer and release it later.

However, if I just want to READ the bytearray jbBase, how could I get the pointer of the jbBase but not using GetPrimitiveArrayCritical ?

Any suggestion would be appreciated. Thanks a lot.

2条回答
我欲成王,谁敢阻挡
2楼-- · 2019-05-06 19:44

I use the following to read byte arrays...

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

You still need to release it as that stops the Garbage collector getting rid of it potentially while you are still using it.

查看更多
干净又极端
3楼-- · 2019-05-06 20:08

GetByteArrayElements method can not guarantee that your program use reference or copy. JNI return isCopy flag for state it copied object or pinned it(pin means reference). If you dont want to copy it never, you havent to use GetArrayElements methods, because it always returns copy(JVM decides copy or not and probably copy prefered because copy eases burden of Garbage Collector). I tried it and I saw that my ram increased when sent a big array. You can also see that at below link:

IBM copy and pin (look at copy and pin subject from tree view)

As document says,GetPrimitiveArrayCritical returns the direct heap address of a Java array, disabling garbage collection until the corresponding ReleasePrimitiveArrayCritical is called. So you must use that GetPrimitiveArrayCritical, if you dont want to copy(u need that when you have a big array). If we look at your code, you can get array one by one as below(I assumed you sent int array as a jobject to JNI function):

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);

Important Note: You cannot GetArrayLength after GetPrimitiveArrayCritical because JNI doesn't permit program to call any JNI function for same object between get critical and release methods.

查看更多
登录 后发表回答