Как читать байтовый массив в JNI? - PullRequest
4 голосов
/ 18 июля 2011

Можно ли ссылаться на весь байтовый массив в JNI, но не вызывать ни одной копии?

В нативном C-коде у меня есть байт-массив, передаваемый из Java, и я просто хочу сравнить некоторые данные с этим байт-массивом, поэтому я не хочу делать какую-либо копию памяти. Возможно ли это?

Я знаю, что мог бы получить указатель на байт-массив в native, используя что-то вроде GetPrimitiveArrayCritical

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, чтобы получить его указатель и выпустить его позже.

Однако, если я просто хочу ЧИТАТЬ байтовый массив jbBase, как я могу получить указатель на jbBase, но не используя GetPrimitiveArrayCritical?

Любое предложение будет оценено. Большое спасибо.

Ответы [ 2 ]

10 голосов
/ 18 июля 2011

Я использую следующее для чтения байтовых массивов ...

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

Вам все еще нужно освободить его, так как это остановит сборщик мусора, потенциально избавляясь от него, пока вы все еще используете его.

6 голосов
/ 12 сентября 2014

Метод GetByteArrayElements не может гарантировать, что ваша программа использует ссылку или копию.JNI возвращает флаг isCopy для состояния, в котором он скопировал объект или закрепил его (pin означает ссылку).Если вы не хотите копировать его никогда, вам не нужно использовать методы GetArrayElements, потому что он всегда возвращает копию (JVM решает, копировать или нет, и, вероятно, копирование предпочтительнее, потому что копирование облегчает работу сборщика мусора).Я попробовал это и увидел, что мой баран увеличился при отправке большого массива.Вы также можете видеть, что по ссылке ниже:

IBM copy и pin (посмотрите на объект копирования и pin из дерева)

Как сказано в документе, GetPrimitiveArrayCritical возвращает прямоеадрес кучи массива Java, отключая сборку мусора до тех пор, пока не будет вызван соответствующий ReleasePrimitiveArrayCritical.Таким образом, вы должны использовать этот GetPrimitiveArrayCritical, если вы не хотите копировать (вам это нужно, когда у вас большой массив).Если мы посмотрим на ваш код, вы можете получить массив один за другим, как показано ниже (я предположил, что вы отправили массив int в качестве задания для функции 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);

Важное примечание: вы не можете получить GetArrayLength после GetPrimitiveArrayCritical, потому что JNIне позволяет программе вызывать какую-либо функцию JNI для одного и того же объекта между методами получения критического значения и выпуска.

...