【发布时间】:2011-06-18 00:01:07
【问题描述】:
我在 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 秒。
【问题讨论】:
-
等等,
ByteBuffer.asIntBuffer怎么了?你真的需要int[]吗? -
...此外,如果您愿意,可以在 IntBuffer 上调用 .array()。
-
.array() 为 Java 中直接分配的数组的 ByteBuffer 和 IntBuffer 引发 Unsupported 异常。我真的很想访问 int[] 这样我就可以在 Java 中做一些不太密集的图像处理工作,例如通过检查哪些像素高于/低于亮度阈值将图像转换为黑白。在 Android 中对每个像素使用 IntBuffer get/put 会太慢而且很笨拙。
-
@rebeccaT,将代码更改为使用 IntBuffer 而不是 int[] 并使用直接缓冲区
-
@rebeccaT,如果 put/get 这么慢,那就是大错特错了。这些方法应该被内联并编译为非常简单的 CPU 指令w/o 任何虚拟方法调用。是的,我建议您转储 int[] 并始终使用直接 IntBuffer
标签: java android c java-native-interface android-ndk