首页 > 解决方案 > Netty 使用来自池化直接 ByteBuf 的 ByteBuffer

问题描述

我试图了解有关 netty 的 ByteBuf 及其与 nio.ByteBuffer 的关系的一些事情。

我试图解决的问题是我的服务器必须返回位于服务器上的文件的随机部分——这是使用 nio.FileChannel 实现的,而 FChannel 取决于 nio.ByteBuffer。

据我了解,分配直接 ByteBuffer 应该是池化的 - 但 nio 中没有本机池实现 - 我的应用程序应该添加这样的层,所以我不会为每个请求创建直接缓冲区而付出代价。

我的应用程序使用 netty 作为服务器,所以我认为我可以使用 netty 的池化直接 ByteBuff 并访问它使用的 ByteBuffer

var byteBuf = ctx.alloc().directBuffer(1024); // (1)
var chunkHolder = byteBuf.nioBuffer(0, byteBuf.capacity()); // (2)

所以一切都按预期工作,但.nioBuffer.nioBuffers创建缓冲区的副本 - 不仅仅是 ByteBuff 上的视图,因此在写入chunkHolder位置/限制/等后byteBuf保持不变!

我必须使用

var flip = chunkHolder.flip(); // (2)
var content = Unpooled.wrappedBuffer(flip);
ctx.writeAndFlush(content)
   .addListener(f -> byteBuf.release()); (1)

所以再次创建对象,唯一的好处是没有复制该内存-如果我没记错的话。

问题:我可以做一些更聪明的事情,以便在 tcp 传输和文件读取之间没有数据复制,并且垃圾最少?nio 是否有助于维护直接的 ByteBuffers?

我想到的最好的想法是用类似 ByteBuffer 的实现包装 BytBuf,并将所有写操作代理回底层 byteBuf。

PS:我也看过io/netty/channel/DefaultFileRegion.java它与 nio.FileChannel 一起使用,但在幕后 netty 直接使用 nio

raf = new RandomAccessFile(filePath, "r");
ctx.write(new DefaultFileRegion(raf.getChannel(), 0, length));

标签: javanettyniobytebufferzero-copy

解决方案


FileRegion 将为您进行零拷贝传输,因为它在FileChannel#transferTo()内部使用 JDK。在这种情况下,这将是产生最少垃圾的途径。


推荐阅读