大部分的场景下,Netty的接收和发送ByteBuffer的过程中,一般来说会使用直接内存进行Socket通道读写,使用JVM的堆内存进行业务处理,会涉及到直接内存、堆内存之间的数据复制。但是,内存的数据复制,其实是效率非常低的,Netty提供了多种方法,帮助
应用程序减少内存的复制。
Netty的零拷贝主要体现在五个方面:
(1)Netty提供CompositeByteBuf组合缓冲区类, 可以将多个ByteBuf合并为一个逻辑上的ByteBuf, 避免了各个ByteBuf之间的拷贝。
(2)Netty提供了ByteBuf的浅层复制操作(slice、duplicate),可以将ByteBuf分解为多个共享同一个存储区域的ByteBuf, 避免内存的拷贝。
(3)在使用Netty进行文件传输时,可以调用FileRegion包装的transferTo方法,直接将文件缓冲区的数据发送到目标Channel,避免普通的循环读取文件数据和写入通道所导致的内存拷贝问题。
(4)在将一个byte数组转换为一个ByteBuf对象的场景,Netty提供了一系列的包装类,避免了转换过程中的内存拷贝。
(5)如果Channel接收和发送ByteBuf都使用direct直接内存进行Socket读写,不需要进行缓冲区的二次拷贝。但是,如果使用JVM的堆内存进行Socket读写,JVM会将堆内存Buffer拷贝一份到直接内存中,然后才写入Socket中,相比于使用直接内存,这种情况在发送过程中会多出一次缓冲区的内存拷贝。所以,在发送ByteBuffer到Socket时,尽量使用直接内存而不是JVM堆内存。
:::tips Netty 中的零拷贝和操作系统层面上的零拷贝是有区别的,不能混淆,我们所说的Netty 零拷贝完全是基于(Java 层面)或者说用户空间的,它的更多的是偏向于应用中的数据操作优化,而不是系统层面的操作优化。 :::