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

Sha*_*hay 6 c++ java java-native-interface native

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

env->NewDirectByteBuffer
env->NewByteArray
Run Code Online (Sandbox Code Playgroud)

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

例如,此代码是否可以正常运行:

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

另一个例子:

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

字符串在堆栈上创建。这段代码会一直工作还是我需要在堆上创建这些字符串并负责在 java 使用完后删除它

Whe*_*zil 6

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

即使您可以保证这一点,也要意识到 Java 的 GC 是不确定的。很容易认为您的 DirectByteBuffer 不再被使用,但同时它在未回收的对象中徘徊,最终被 GC 捕获,GC 可能会调用一些不小心接触 DirectByteBuffer 的 finalize() 方法,还有——卡布罗伊!实际上,除了在应用程序的生命周期中永远不会消失的“共享内存”块之外,很难做出这些保证。

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

  1. 调用 NewByteArray() 和 SetByteArrayRegion(),将生成的 jBytearray 返回给 Java 就不用担心了。
  2. 如果需要性能,请将 byte[] 从 Java 传递给 C++ 并让 C++ 填充它。您可能需要两次 C++ 调用,一次获取大小,另一次获取数据。
  3. 如果数据很大,请使用 NewDirectBtyeBuffer 并确保 C++ 数据“永远”保留,或者直到您确定 DirectByteBuffer 已被处理。

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