回答
Linux 的零拷贝主要是在 OS 层,而 Netty 的零拷贝则不同,它完全是在应用层,我们可以理解为用户态层次的,Netty 的零拷贝更加偏向于优化数据操作这样的概念,主要体现在下面四个方面:
- Netty 提供了
CompositeByteBuf
类,可以将多个 ByteBuf 合并成一个逻辑上的 ByteBuf,避免了各个 ByteBuf 之间的拷贝。 - Netty 提供了
slice
操作,可以将一个 ByteBuf 切分成多个 ByteBuf,这些 ByteBuf 共享同一个存储区域的 ByteBuf,避免了内存的拷贝。 - Netty 提供了
wrap
操作,可以将 byte[] 数组、ByteBuf、ByteBuffer 等包装成一个 Netty ByteBuf 对象, 进而避免了拷贝操作。 - Netty 提供了 FileRegion,通过 FileRegion 可以将文件缓冲区的数据直接传输给目标 Channel,这样就避免了传统方式通过循环 write 方式导致的内存拷贝问题。
详情
CompositeByteBuf
我们在传输数据的时候一般都会定义消息头和消息体,消息头和消息体一般都存放在两个 ByteBuf 中,如下:
ByteBuf header = ...
ByteBuf body = ...
在发送消息时,我们希望将消息头和消息体合并在一个 ByteBuf 中发送,如下:
ByteBuf byteBuf = ...;
byteBuf.writeBytes(header);
byteBuf.writeBytes(body);
这样粗看是没有什么问题的,但是我们仔细详细你会发现这里涉及了两次的数据拷贝,那有没有更加高效的处理方式呢?使用 CompositeByteBuf
:
CompositeByteBuf compositeByteBuf = Unpooled.compositeBuffer();
compositeByteBuf.addComponents(true, header, body);
我们首先定义一个 CompositeByteBuf
对象,然后调用它的 addComponents()
将 header 和 body 进行合并,这样 header 和 body 就合并成了一个逻辑上合并的 ByteBuf 了,如下: