首页 > 解决方案 > 有没有办法用 JNI 设置 DirectByteBuffer 内存?

问题描述

出于某种原因,我必须使用当前无法直接从 JVM 访问的 Linux 特定 API,并且需要设计一个接受的方法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);

如何char*通过给定ByteBuffer的 with 获得JNI?我可以使用DirectBuffer,但我将仅限于DirectBuffers 并且除了生成以下警告:

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

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

标签: javacjvmjava-native-interface

解决方案


假设您将自己限制在公共类及其公共 API 中,您有两种相对有效的替代方案来解决该问题,但它们的共同点是它们依赖于将数据放入 Javabyte[]中。这并不难:

/* 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),但在这种情况下,您应该使用非Critical版本Get/Release例程的。

话虽如此,您将数据一直输入到 a 中的两个主要选择ByteBuffer

  • 如果是缓冲区hasArray(),则通过缓冲区的方法获取byte[]上述过程。array()做完了。

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

我不建议假设特定的具体ByteBuffer子类或依赖非公共方法。如果性能是高优先级,那可能值得考虑,但您似乎说不是。


推荐阅读