Подтвердить что ты не робот

Отправка int [] s между Java и C

У меня есть код обработки изображений Java на Android, который действует на два больших массива int. В большинстве случаев Java достаточно быстро, но мне нужно использовать C через JNI и NDK для ускорения нескольких операций.

Единственный способ, которым я знаю, что я могу передать данные из массивов int в C, - использовать ByteBuffer.allocateDirect для создания нового буфера, скопировать данные на него и затем сделать код C действующим в буфере.

Однако я не могу видеть, как я могу манипулировать данными в этом буфере в Java, как если бы буфер был int [] или байтом []. Например, вызов ByteBuffer.array() завершится неудачно во вновь созданном буфере. Есть ли способ сделать эту работу?

У меня ограниченная память и вы хотите уменьшить количество массивов/буферов, которые мне нужны. Например, было бы неплохо, если бы я мог использовать IntBuffer.wrap(new int [...]) для создания буфера, а затем манипулировать массивом, поддерживающим буфер непосредственно на Java, но я не могу этого сделать, потому что единственное, что кажется работа здесь для JNI - ByteBuffer.allocateDirect.

Существуют ли другие способы отправки данных между C и Java? Могу ли я как-то выделить память на стороне С и отправить Java прямо туда?

Изменить: сравнительный пример сравнения использования буфера с int [] use:

int size = 1000;
IntBuffer allocateDirect = java.nio.ByteBuffer.allocateDirect(4 * size).asIntBuffer();
for (int i = 0; i < 100; ++i)
{
  for (int x = 0; x < size; ++x)
  {
    int v = allocateDirect.get(x);
    allocateDirect.put(x, v + 1);
  }
}

int[] intArray = new int[size];
for (int i = 0; i < 100; ++i)
{
  for (int x = 0; x < size; ++x)
  {
    int v = intArray[x];
    intArray[x] = v + 1;
  }
}

На телефоне Droid версия буфера занимает ~ 10 секунд, и версия массива занимает ~ 0.01 секунды.

4b9b3361

Ответ 1

Из http://java.sun.com/docs/books/jni/html/objtypes.html используйте JNI Get/Release<TYPE>ArrayElements(...)

В этом примере я передам массив (для параметра sake, it int array = new int[10], а затем заполните его 0-9

 JNIEXPORT jint JNICALL 
 Java_IntArray_doStuffArray(JNIEnv *env, jobject obj, jintArray arr)
 {

     // initializations, declarations, etc
     jint *c_array;
     jint i = 0;

     // get a pointer to the array
     c_array = (*env)->GetIntArrayElements(env, arr, NULL);

     // do some exception checking
     if (c_array == NULL) {
         return -1; /* exception occurred */
     }

     // do stuff to the array
     for (i=0; i<10; i++) {
         c_array[i] = i;
     }

     // release the memory so java can have it again
     (*env)->ReleaseIntArrayElements(env, arr, c_array, 0);

     // return something, or not.. it up to you
     return 0;
 }

Раздел 3.3 изучения и, в частности, 3.3.2 - это позволит вам получить указатель на массив в java-памяти, изменить его и выпустить, что фактически позволяет вам изменять массив в собственном коде.

Я только что использовал его в своем собственном проекте (с короткими массивами), и он отлично работает:)

Ответ 2

Если вы используете прямые выделенные буферы, вы можете получить доступ к базовому массиву непосредственно из C, используя функцию GetDirectBufferAddress. Это предотвращает возможность копирования областей области.

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

Затем, в качестве эфемерных состояний, вы можете использовать ByteBuffer.asIntBuffer() и family для доступа к буфере таким образом, который эмулирует массивы различных Java-примитивов.

http://download.oracle.com/javase/1.4.2/docs/guide/jni/jni-14.html

Ответ 3

Вы можете использовать обратный вызов для отправки данных из собственного уровня в Java.

В Java-слое: в моем родном классе у меня есть следующие методы:

//Native method
public native String getStrData(int size);

//Callback method
public void addData(char[] native_data, int size) {

    ...

}

В исходном слое: в моей собственной реализации:

JNIEXPORT jstring JNICALL Java_com_pkg_NativeClass_getStrData 
   (JNIEnv *env, jobject obj, jint size) {
     ...

     jclass native_class;           /* Callback: native class */
     jmethodID native_method_id;    /* Callback: native method id */
     jcharArray row;                /* Callback: native data */

     ...

    /* Start Callback: Native to Java  */   
    native_class = (*env)->GetObjectClass(env, obj);
    native_method_id = (*env)->GetMethodID(env, native_class, "addData", "([CI)V");
    if (native_method_id == 0) {
        return (jstring)ERR_NATIVE_METHODID;
    }
    row = (jcharArray)(*env)->NewCharArray(env, size);
    /* jc has the data to be sent to Java */
    (*env)->SetCharArrayRegion(env, (jcharArray)row, (jsize)0, size, (jchar *)jc);

    (*env)->CallVoidMethod(env, obj, native_method_id, row, size);
    /* End Callback */

     ...
}