有没有办法用 JNI 设置 DirectByteBuffer 内存?

Is there a way to set DirectByteBuffer memory with JNI?

出于某种原因,我必须使用 Linux-specific API,目前无法从 JVM 直接访问它,需要设计一个方法来接受 ByteBuffer (这绝对不是因为某些性能原因)。这是它的样子:

//I need to call device-specific ioctl here
//and fill the ByteBuffer
public static native long putIntoByteBuffer(int fd, ByteBuffer buf);

生成的头文件为

JNIEXPORT jlong JNICALL Java_net_abcomm_PlatformSpecific_putIntoByteBuffer
  (JNIEnv *, jclass, jint, jobject);

如何通过给定的ByteBufferJNI得到char*?我可以使用 DirectBuffer,但我将仅限于 DirectBuffer,此外还会生成以下警告:

warning: DirectBuffer is internal proprietary API and may be removed in a 
future release
import sun.nio.ch.DirectBuffer;

还有 GetDirectBufferAddress 返回 void* 但仅限于 DirectBuffers。

假设您将自己限制在 public 类 和他们的 public API,您有两个相对有效的替代方案来解决问题,但它们有共同点他们依靠将数据放入 Java byte[]。这并不难:

/* error checks omitted for brevity; these are *not* optional */

char *cBytes = /* ... */;
size_t numCBytes = /* ... */;
jbyteArray javaBytes = /* ... */;

jsize numBytes = (*env)->GetArrayLength(env, javaBytes);
jbyte *bytes = (*env)->GetPrimitiveArrayCritical(env, javaBytes, NULL);
/* It is pretty safe to assume that jbyte is a character type, such as signed
   char, in any C implementation that supports the JNI at all */
/* Assumes numCBytes <= numBytes; adjust as necessary if that may not be true: */
memcpy(bytes, cBytes, numCBytes);
(*env)->ReleasePrimitiveArrayCritical(env, javaBytes, bytes, 0);

请注意,如果 JNI 函数执行某种 I/O 来获取字节,它可能能够将它们直接读入 bytes(取决于本机要求,而不是 JNI) , 但在这种情况下,您应该使用 Get/Release 例程的非 Critical 版本。

话虽如此,将数据一直导入 ByteBuffer 的两个主要替代方法是

  • 如果缓冲区hasArray(),则通过缓冲区的array()方法获取上述过程的byte[]。大功告成。

  • 如果缓冲区没有hasArray(),或者如果您不想检查,则通过重新实例化它来获得byte[],并在通过上述过程,通过缓冲区的批量put(byte[])put(byte[], int, int)方法将内容复制到缓冲区中。显然,这涉及相对于另一个替代方案的额外副本,并且它使用额外的临时对象。

我不建议假设一个特定的具体 ByteBuffer 子类或依赖非 public 方法。如果性能是重中之重,那可能值得考虑,但您似乎说不是。