netty中的零拷贝

本文深入探讨了Netty中的零拷贝技术,详细解释了Netty如何通过使用DirectBuffers、CompositeBuffers以及FileChannel.transferTo方法实现数据传输的零拷贝,减少CPU资源消耗,提高应用性能。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

Netty中的零拷贝与我们传统理解的零拷贝不太一样。
传统的零拷贝指的是数据传输过程中,不需要CPU进行数据的拷贝,即零拷贝是不需要数据在用户空间与内核中间之间的拷贝。

一、传统的零拷贝含义

看从服务端的磁盘上读取文件,然后通过网络协议,发送给客户端的场景
在这里插入图片描述
DMA(Direct Memory Access)直接内存存取:主存和I/O设备之间有一条数据通路,如此一来,主存和I/O设备之间传输数据就不用中断CPU了。

这需要四次数据拷贝和四次上下文切换:
1、把服务端磁盘上的数据copy到操作系统内核的缓冲区里,这个过程是DMA(Direct Memory Access)搬运的
2、 把内核缓冲区的数据copy到用户缓冲区里,于是我们的应用程序就可以使用这部分数据了,这个copy过程是CPU完成的
3、把刚才copy到用户缓冲区里的数据,再copy到内核的socket缓冲区里,这个过程依然还是由CPU完成的。
4、把内核的socket缓冲区里的数据,copy到网卡缓冲区里,这个过程又是由DMA搬运的。
明显上面的第二步和第三步是没有必要的,通过java的FileChannel.transferTo方法,可以避免上面两次多余的拷贝(当然这需要底层操作系统支持),transferTo方法实际是实现了操作系统的sendfile。

  1. 调用transferTo,数据从文件由DMA引擎拷贝到操作系统内核缓冲区
  2. 接着DMA从操作系统内核缓冲区将数据拷贝到网卡接口buffer
    上面的两次操作都不需要CPU参与,所以就达到了零拷贝。

二、netty中的零拷贝

Netty中也用到了FileChannel.transferTo方法,所以Netty的零拷贝也包括上面将的操作系统级别的零拷贝。除此之外,在ByteBuf的实现上,Netty也提供了零拷贝的一些实现。
关于ByteBuffer,Netty提供了两个接口:
1.ByteBuf
2. ByteBufHolder

对于ByteBuf,Netty提供了多种实现:
1.Heap ByteBuf: 直接在堆内存分配
2.Direct ByteBuf:直接在堆外内存分配
3.CompositeByteBuf:组合Buffer

1. Direct Buffers

直接在内存区域分配空间,而不是在堆内存中分配。如果使用传统的堆内存分配,当我们需要将数据通过socket发送的时候,就需要从堆内存拷贝到直接内存,然后再由直接内存拷贝到网卡接口层。
Netty提供的直接Buffer,直接将数据分配到内存空间,从而避免了数据的拷贝,实现了零拷贝。

2. Composite Buffers

传统的ByteBuffer,如果需要将两个ByteBuffer中的数据组合到一起,我们需要首先创建一个size=size1+size2大小的新的数组,然后将两个数组中的数据拷贝到新的数组中。但是使用Netty提供的组合ByteBuf,就可以避免这样的操作,因为CompositeByteBuf并没有真正将多个Buffer组合起来,而是保存了它们的引用,从而避免了数据的拷贝,实现了零拷贝。

3. 对于FileChannel.transferTo的使用

Netty中使用了FileChannel的transferTo方法,该方法依赖于操作系统实现零拷贝。

总结

Netty的零拷贝体现在三个方面:

  1. Netty的接收和发送ByteBuffer采用DIRECT BUFFERS,使用堆外直接内存进行Socket读写,不需要从 堆内内存 copy 到直接内存 再copy到socket,而是 直接写到堆外内存,由堆外内存(即操作系统直接内存)copy到socket。

  2. Netty提供了组合Buffer对象,可以聚合多个ByteBuffer对象,用户可以像操作一个Buffer那样方便的对组合Buffer进行操作,避免了传统通过内存拷贝的方式将几个小Buffer合并成一个大的Buffer。

  3. Netty的文件传输采用了transferTo方法,它可以直接将文件缓冲区的数据发送到目标Channel,避免了传统通过循环write方式导致的内存拷贝问题。

direct buffer和heap buffer有什么区别?
1、heap buffer在堆上分配内存,有JVM负责GC,可直接想象成一个字节数组的包装类。
2、direct buffer是通过JNI在JVM外的内存中分配内存,JVM不会负责他的GC,但是当direct buffer包装类被回收时,会通过java reference机制来释放该内存块。(但Direct buffer的java对象是归GC管的,只要GC回收了他的java对象,操作系统才会释放direct buffer所申请的空间)

优劣势对比:
1、创建和释放direct buffer比heap direct代价高
2、当我们把一个direct buffer写入channel时,好比”操作系统内核缓冲区“的内容直接写入了channel,避免了内核态到用户态的数据copy。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值