使用JNI有效地将GPB序列化数据从Java传递到C ++

时间:2014-02-27 07:42:29

标签: java java-native-interface protocol-buffers outputstream bytebuffer

这些天我正在寻找一种方法将复杂的数据结构从Java传递到本机(C ++)DLL,反之亦然。在阅读了很多关于JNI的文章及其开销之后,我开始寻找一种有效的方法来序列化Java / native端的数据,并将其作为一大块数据传递给另一端。这样,可以保存许多JNI调用。 目前,我使用Google Protocol Buffers序列化许多复杂类,并通过单个JNI调用将此数据传递给本机层。 看起来不错。例如,Java端的4000个小类的序列化,本机端的JNI调用和反序列化在i7上需要大约1.6ms。

java端的序列化是通过调用GPB_GENERATED_CLASS。 build.toByteArray()来完成的,它会在每次调用时创建一个新的字节数组。 之后,使用 put()函数将数组数据复制到直接ByteBuffer中。

Google协议缓冲区序列化程序提供了另一个能够将序列化数据写入OutputStream的函数。

我的问题是:

  1. 有没有办法将序列化数据传递给JNI(本机),没有复制并在每次调用时创建新对象?
  2. 有没有办法分配ByteArrays或DirectByteBuffers一次并使用它们将数据从Java传递到JNI,反之亦然(使用OutputStream?)?
  3. 非常欢迎任何可能提高性能并节省垃圾收集操作的技巧。
  4. 谢谢

1 个答案:

答案 0 :(得分:2)

Google协议缓冲区(GPB)邮件实施还提供了writeTo方法。

ByteArrayOutputStream非常接近您要查找的内容,但是,无论何时访问内部字节数组,它都会创建一个新副本,这听起来不像您要查找的内容。但是,如果您创建自己的OutputStream实现(类似于ByteArrayOutputStream),则可以控制内部字节数组的生命周期,或DirectByteBuffer。这应该允许您提高性能并减少短期对象。

writeTo

void writeTo(OutputStream output)
  

序列化消息并将其写入输出。这只是一件小事   writeTo(CodedOutputStream)的包装器。这不会冲洗或   关闭溪流。

     
    

注意:协议缓冲区不是自定义的。因此,如果你     在消息之后将更多数据写入流,你必须以某种方式     确保接收端的解析器不会将其解释为     成为协议消息的一部分。这可以通过例如完成。通过写作     数据之前的消息大小,然后确保限制     在接收端输入该大小(例如通过包装     InputStream中的一个限制输入)。或者,只需使用     writeDelimitedTo(OutputStream中)。

  
     

抛出:        IOException抛出IOException