В функции JNI, когда я изменяю массив на месте, который был передан из кода Java, массив не изменяет - PullRequest
0 голосов
/ 08 февраля 2019

Я передаю массив int из Java в нативный метод.Затем в функции JNI я создал указатель на массив int с помощью GetIntArrayElements () и передал в качестве аргумента * isCopy JNI_FALSE.Я предположил, что это не создаст копию исходного массива, и я мог бы изменить массив на месте.Затем я использую ReleaseIntArrayElements () и передаю в качестве аргумента режима JNI_ABORT, чтобы просто освободить буфер.Но это не сработало.

Из документации JNI:

  • mode 0: скопировать обратно содержимое и освободить буфер elems
  • mode JNI_COMMIT: скопировать обратносодержимое, но не освобождайте буфер elems
  • режим JNI_ABORT: освобождайте буфер без копирования возможных изменений

Это при попытке использовать режим "0" в ReleaseIntArrayElements (), чтоработал отлично.Но я не понимаю, почему я не создал копию исходного массива, а режим «0» копирует содержимое.

Я полагаю, что JNI всегда создает копию исходного массива.Но тогда аргумент * isCopy в GetIntArrayElements () теряет смысл.Так что же на самом деле происходит с этим?

ЭТО МОЯ ФУНКЦИЯ ДЖНИ

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

Ответы [ 2 ]

0 голосов
/ 08 февраля 2019

Вы неправильно использовали jboolean *isCopy.Это выходной параметр, который вы должны проверить после фактического вызова env->GetIntArrayElements(tbl, isCopy);.Если возвращается JNI_FALSE, то копия не производится.

Это необходимо, поскольку GC может перемещать элементы из одного местоположения в другое непредсказуемо , и вы всегда должны копировать изменения обратно в оригинал.массив Java.Потому что вы никогда не знаете расположение в памяти фактического массива Java.

Если вы не хотите, чтобы копия была сделана, вы, вероятно, ищете critical версию метода.Вот что сказано в документах JNI:

Эти ограничения повышают вероятность того, что собственный код> получит не скопированную версию массива, даже если виртуальная машина> не поддерживает закрепление

Это не означает, что JVM будет отключать сборку мусора, пока вы держите критическую секцию, хотя, скорее всего, это будет сделано.

Emp.Mine:

Например, виртуальная машина может временно отключить сборку мусора, когда собственный код содержит указатель на массив, полученный с помощью GetPrimitiveArrayCritical

0 голосов
/ 08 февраля 2019

Вы, похоже, неправильно поняли назначение параметра isCopy для GetIntArrayElements.Это не входной параметр, сообщающий GetIntArrayElements, должен ли он предоставить вам копию данных массива;это выходной параметр, который GetIntArrayElements может использовать, чтобы сообщить вам , создана ли она копией.

Из документации:

Если isCopy isне NULL, тогда * isCopy устанавливается в JNI_TRUE, если копия сделана;или он установлен в JNI_FALSE, если копия не сделана.

Итак, если вы передаете не-NULL jboolean*, вы можете проверить это значение позже.Если вы передадите NULL, вы не получите эту информацию.Например, если вы намереваетесь только прочитать из данных, то знать, является ли это копией, может быть неинтересно, поскольку вы, вероятно, просто собираетесь использовать JNI_ABORT при освобождении элементов.

...