Netty 使用来自池化直接 ByteBuf 的 ByteBuffer

Netty using ByteBuffer from pooled direct ByteBuf

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

我尝试解决的问题是我的服务器必须 return 位于服务器上的文件的随机部分 - 这是使用 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 positions/limits/etc 之后byteBuf保持不变!

我必须使用

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

所以对象又被创建了,唯一的好处是内存没有被复制 - 如果我没记错的话.

问题:我可以做一些更聪明的事情,以便在 tcp 传输和文件读取之间没有数据复制,垃圾最少吗? nio 是否以某种方式帮助维护直接字节缓冲区?

我想到的最好的想法是用类似 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));

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