我的C库中有一个unsigned char*
,我正在调用一个JNI导出的函数,需要用这个数据设置一个java对象,最好是byte[]
。
但是这个函数会经常被调用,并且需要复制很多数据。
是否可以使用ByteBuffer并将该ByteBuffer的指针分配给我的unsigned char*
?或者它只是反过来工作?
我是否可以在不复制数据的情况下执行此操作?什么是访问它的最佳方式?
unsigned char*
中的数据大小已知。
答案 0 :(得分:4)
考虑到您提供的信息很少,这是一个可能的解决方案。
在Java方面,你会有:
package com.stackoverflow;
public class JNIQuestion
{
static native void fillByteArray(byte[] buffer);
}
在C方面你会得到:
JNIEXPORT void JNICALL Java_com_stackoverflow_JNIQuestion_fillByteArray(JNIEnv* env, jbyteArray array)
{
jboolean isCopy;
jbyte* buffer = (*env)->GetByteArrayElements(env, array, &isCopy);
jsize length = (*env)->GetArrayLength(env, array);
jsize i;
// do something with the buffer here, replace with something meaningful
// PAY ATTENTION TO BUFFER OVERFLOW, DO NOT WRITE BEYOND BUFFER LENGTH
for (i = 0; i < length; ++i)
buffer[i] = i;
// here it is important to use 0 so that JNI takes care of copying
// the data back to the Java side in case GetByteArrayElements returned a copy
(*env)->ReleaseByteArrayElements(env, buffer, 0);
}
使用直接ByteBuffer
(ByteBuffer.allocateDirect()
)也是一种可行的解决方案。但是,当我需要从Java端填充缓冲区中非常精确的偏移量时,我只使用直接ByteBuffer
。
关于性能,使用byte[]
的解决方案应该是令人满意的,因为JVM可能会固定字节数组而不是在调用GetByteArrayElements()
时复制它。
一般来说,您需要最小化JNI调用的数量,这意味着从C端访问对象字段或从C端分配Java将对性能产生影响。
无论如何,首先进行配置,然后进行优化。
PS:我没有尝试编译代码,可能有拼写错误。请参阅JNI Guide和JNI Tutorial。