在 Java 和 C 之间发送 int[]s

我在Android中有一些图像处理Java代码,可以作用于两个大型int数组。大多数时候,Java足够快,但我需要通过JNI和NDK使用C来加快一些操作。

我知道我可以将数据从int数组传递到C的唯一方法是使用ByteBuffer.allocateDirect创建一个新的缓冲区,将数据复制到该缓冲区,然后使C代码对缓冲区执行操作。

但是,我看不出任何方法可以在Java中操作此缓冲区中的数据,就好像缓冲区是int[]或byte[]一样。例如,对 ByteBuffer.array() 的调用将在新创建的缓冲区上失败。有没有办法做到这一点?

我的内存有限,想要减少所需的数组/缓冲区数。例如,如果我可以使用IntBuffer.wrap(new int[...])来创建缓冲区,然后直接在Java中操作支持缓冲区的数组,那就太好了,但我不能这样做,因为这里似乎唯一适用于JNI的是ByteBuffer.allocateDirect。

有没有其他方法可以在C和Java之间来回发送数据?我可以以某种方式在C端分配内存并让Java将数据直接发送到那里吗?

编辑:比较缓冲区使用与int[]使用的基准测试:

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秒。


答案 1

http://java.sun.com/docs/books/jni/html/objtypes.html,使用 JNI 的Get/Release<TYPE>ArrayElements(...)

在这个例子中,我将传递一个数组(为了参数的缘故,它是,然后用0-9填充它int array = new int[10]

 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's 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


推荐