NewDirectByteBuffer 是否在本机代码中创建副本

does NewDirectByteBuffer create a copy in native code

我正在用 C++ 创建两个数组,将在 java 端读取:

env->NewDirectByteBuffer
env->NewByteArray

这些函数会复制我发送的缓冲区吗? 我是否需要在 C++ 端的堆上创建缓冲区,还是可以在堆栈上创建缓冲区,因为 jvm 会复制它?

例如这个代码 运行 ok:

std::string stam = "12345";
const char *buff = stam.c_str();
jobject directBuff = env->NewDirectByteBuffer((void*)buff, (jlong) stam.length() );

另一个例子:

std::string md5 "12345";    
jbyteArray md5ByteArray = env->NewByteArray((jsize) (md5.length()));
env->SetByteArrayRegion(md5ByteArray, 0, (jsize) (md5.length()), (jbyte*)    
 md5.c_str());

字符串在堆栈上创建。此代码是否始终有效,或者我是否需要在堆上创建这些字符串并负责在 java 完成使用后删除它

  • NewDirectByteBuffer: "Allocates and returns a direct java.nio.ByteBuffer referred to the block of memory starting at the memory address address and extending capacity bytes.

    "Native code that calls this function and returns the resulting byte-buffer object to Java-level code should ensure that the buffer refers to a valid region of memory that is accessible for reading and, if appropriate, writing. An attempt to access an invalid memory location from Java code will either return an arbitrary value, have no visible effect, or cause an unspecified exception to be thrown.".

    那里没有复制。

  • New<Primitive>Array:只有参数JNIEnv *length,所以没有什么可复制的。

  • Set<Primitive>Array: "A family of functions that copies back a region of a primitive array from a buffer."

您对 DirectByteBuffer 的使用几乎肯定会以惊人的、核心转储和不可预测的方式失败。它的行为可能因 JVM 实现和操作系统而异。问题是您的直接内存 必须 在 DirectByteBuffer 的生命周期内保持有效。由于您的字符串在堆栈上,它会很快超出范围。同时 Java 代码可能会或可能不会继续使用 DirectByteBuffer,这取决于它是什么。你也在写 Java 代码吗?你能保证它对 DirectByteBuffer 的使用会在字符串超出范围之前完成吗?

即使您可以保证这一点,也要意识到 Java 的 GC 是不确定的。人们很容易认为您的 DirectByteBuffer 不再被使用,但与此同时它在未回收的对象中徘徊,最终被 GC 吸走,GC 可能会调用一些意外触及 DirectByteBuffer 的 finalize() 方法,以及——kablooey!实际上,很难做出这些保证,除了 "shared memory" 块 永远不会 在您的应用程序生命周期中消失。

NewDirectByteBuffer 也不是那么快(至少在 Windows 中不是),尽管直觉假设性能就是它的全部。我通过实验发现复制 1000 个字节比创建单个 DirectByteBuffer 更快。让您的 Java 将字节 [] 传递到 C++ 并让 C++ 将字节复制到其中通常 快(咳咳,假设它们适合)。总体而言,我提出以下建议:

  1. 调用 NewByteArray() 和 SetByteArrayRegion(),return 结果 jBytearray 到 Java,不用担心。
  2. 如果性能是 要求,将 byte[] 从 Java 传递给 C++ 并让 C++ 填充它 中。您可能需要两次 C++ 调用,一次获取大小,下一次 获取数据。
  3. 如果数据很大,使用NewDirectBtyeBuffer和 确保 C++ 数据保持在 "forever" 左右,或者直到您 该死的确定 DirectByteBuffer 已被处置。

我还读到 C++ 和 Java 都可以对同一个文件进行内存映射,这对大数据非常有效。