Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/security/4.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
在Java中,如何在不分配堆字节数组的情况下解析直接内存中的Google协议缓冲区?_Java_Garbage Collection_Netty_Protocol Buffers_Bytebuffer - Fatal编程技术网

在Java中,如何在不分配堆字节数组的情况下解析直接内存中的Google协议缓冲区?

在Java中,如何在不分配堆字节数组的情况下解析直接内存中的Google协议缓冲区?,java,garbage-collection,netty,protocol-buffers,bytebuffer,Java,Garbage Collection,Netty,Protocol Buffers,Bytebuffer,我正在尝试将不在JVM堆中的ByteBuf解析为Google协议缓冲区对象。事实上,它是Netty传递给我的直接内存字节缓冲区 这就是我目前正在做的: ByteBuf buf = ...; ByteBufInputStream stream = new ByteBufInputStream(buf); Message msg = MyPbMessage.getDefaultInstance().getParserForType().parseFrom(stream); 这是可行的。然而,我发现

我正在尝试将不在JVM堆中的ByteBuf解析为Google协议缓冲区对象。事实上,它是Netty传递给我的直接内存字节缓冲区

这就是我目前正在做的:

ByteBuf buf = ...;
ByteBufInputStream stream = new ByteBufInputStream(buf);
Message msg = MyPbMessage.getDefaultInstance().getParserForType().parseFrom(stream);
这是可行的。然而,我发现这种类型的解析会在每条消息中引入新的字节数组,并导致大量GC

那么,在创建堆字节数组时有没有办法避免这些问题呢?i、 直接从本机内存解析Google协议缓冲区字节。

您可以这样做。在ThreadLocal中存储一个小缓冲区(1024字节),如果足够的话使用它,并且永远不要在TL中放置更大的缓冲区

只要它能满足大多数请求,它就可以正常工作。如果平均/中间值太大,您可以选择软/弱参考,但是,如果没有一些实际测试,很难判断它是否有帮助

您可以将这些方法结合起来,即在TL中使用强引用的小缓冲区和弱引用的大缓冲区。您可以将缓冲区集中在一起,您可以


。。。但请注意,这一切都有其黑暗的一面。浪费内存,延长缓冲区寿命,导致它们升级到旧一代,而旧一代的垃圾收集成本更高。

您可以尝试在堆字节数组中存储一个,并将Netty的每个字节复制到其中,而不是让protobuf解析器为每条消息分配一个新的字节。@LouisWasserman是的,这是可行的。我只是使用了一个ThreadLocal作为每个消息字节的堆上缓存,它运行良好。但是,我认为还有一个副作用,即缓存的大小,即ThreadLocal中的字节数组,只能越来越大,不能调整。如果我让缓存的大小正好等于消息的字节大小,那么每次分配新的缓存会有什么区别呢?你可以让它增长,但也可以将它存储在线程本地->软/弱引用中,这样它就会得到GCed,你可以从一个小的缓存开始重新开始如果你做
parseFrom(buf.array())
?或者这个
ByteBuf
没有支持数组吗?请注意,无论您在这里做什么,protobuf本身仍然在内部执行大量分配。@KentonVarda此ByteBuf没有备份数组,因为它位于直接内存中。谢谢!看起来这是解决问题的唯一方法,而无需切换到另一个支持零拷贝的协议。可行,但不太优雅。