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

时间:2015-03-01 09:09:16

标签: java c++ java-native-interface native

我在c ++中创建两个数组,将在java端读取:

env->NewDirectByteBuffer
env->NewByteArray

这些功能是否复制我发送的缓冲区? 我是否需要在c ++端在堆上创建缓冲区,或者可以在堆栈上创建它,因为jvm会复制它吗?

例如

此代码运行正常:

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完成后删除它

2 个答案:

答案 0 :(得分:3)

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

即使你能保证这一点,也要认识到Java的GC是不确定的。很容易认为你的DirectByteBuffer不再被使用了,但同时它在无人值守的对象中徘徊,最终被GC覆盖,这可能会调用一些意外触及DirectByteBuffer的finalize()方法,和 - kablooey!在实践中,除了“共享内存”块之外,很难做出这些保证,永远不会在应用程序的生命周期内消失。

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

  1. 调用NewByteArray()和SetByteArrayRegion(),返回结果 jBytearray对Java并没有后顾之忧。
  2. 如果表现是一个 要求,将byte []从Java传递给C ++并让C ++填充它 您可能需要两个C ++调用,一个用于获取大小,另一个用于获取大小 获取数据。
  3. 如果数据量很大,请使用NewDirectBtyeBuffer和 确保C ++数据“永远”存在,或直到你 确定已经处置了DirectByteBuffer。
  4. 我还读到C ++和Java都可以对同一个文件进行内存映射,这对大数据非常有效。

答案 1 :(得分:1)

  • NewDirectByteBuffer:"分配并返回一个直接的java.nio.ByteBuffer,指的是从内存地址开始并扩展容量字节的内存块。

    "调用此函数并将生成的字节缓冲区对象返回到Java级代码的本机代码应确保缓冲区引用可供读取的内存的有效区域,并在适当时写入。尝试从Java代码访问无效的内存位置将返回任意值,没有可见效果,或导致抛出未指定的异常。"。

    没有复制。

  • New<Primitive>Array:只有JNIEnv *length参数,因此无需复制。

  • Set<Primitive>Array:&#34;从缓冲区复制原始数组区域的一系列函数。&#34;