Netty零拷贝

netty的零拷贝技术主要基于以下几点:

1. 堆外内存,也叫直接内存

2. Composite Buffers

3. 文件传输基于linux的sendfile机制

堆外内存

Linux的设计的初衷:给不同的操作给与不同的“权限”。Linux操作系统就将权限等级分为了2个等级,分别就是内核态和用户态。

内核态是属于cpu的特权工作模式,可以操作计算机设备中的任何元件,包括网卡、硬盘、内存等等。

用户态是应用程序的工作模式,只能操作已申请的内存空间,无法操作外围设备。当应用程序需要与网卡、硬盘等外围设备进行交互时,需要通过系统提供的接口,来调用外围设备。

堆内存中的数据如果需要发送到外围设备,需要调用系统的接口,将数据拷贝到堆外内存中,发送到外围设备中。

而Netty的ByteBuffer不经过堆内存,直接在堆外内存中进行读写,省去一步拷贝操作。

需要注意的是,堆外内存只能通过主动调用回收或者Full GC回收,如果使用不当,容易造成内存溢出。

Composite Buffers

Netty提供了Composite Buffers来组合多个buffer。传统的buffer如果要合并的话,需要新建一个buffer,将原来的buffer拷贝到新的buffer中进行合并。而Composite Buffers相当于buffer的集合,保存了每个buffer对象,使物理的buffer合并变为逻辑上的buffer的合并。

文件传输

Netty的文件传输是依赖于操作系统的零拷贝技术。

一般我们读取文件都是调用操作系统接口,操作系统在应用程序读取文件时,会首先判断文件是否在内核缓冲区中,如果不在,则需要将文件从磁盘或socket读取到内核缓冲区中。

在写入文件时,操作系统会将文件先写入内核缓冲区,再写入到socket中。

我们传统做文件拷贝或传输时,会先在应用程序内存中构建一个缓冲区,通过这个缓冲区与操作系统做数据交换。这样无疑会增加了文件的多次拷贝。

传统的文件传输过程如下:

1. 构建byte[]数组来缓冲文件

2. 切换到内核态,将文件先在内核缓冲区中缓存

3. 将内核缓冲区的数据拷贝到应用程序缓冲区的byte[]数组中

4. 切换回用户态

5. 执行写入操作,切换回内核态

6. 将数据再拷贝一份到内核中的socket缓冲区

7. 切换回用户态

8. 操作系统将数据异步刷新到网卡

传统的文件传输过程,会造成操作系统在用户态和内核态多次切换,非常影响性能。

而linux在内核2.1中引入了sendfile操作,过程如下:

1. 读取数据时,sendfile系统调用导致文件内容通过DMA模块被复制到内核缓冲区中

2. 写入数据时,数据直接复制到socket关联的缓冲区(linux内核2.4已删除这一步,取而代之的是,只有记录数据位置和长度的描述符被加入到socket缓冲区中。DMA模块将数据直接从内核缓冲区传递给协议引擎)

3. 最后将socket buffer中的数据copy到网卡设备中(protocol buffer)发送

netty的FileRegion 包下的FileChannel.tranferTo即是基于sendfile机制来实现文件传输的

©著作权归作者所有,转载或内容合作请联系作者
【社区内容提示】社区部分内容疑似由AI辅助生成,浏览时请结合常识与多方信息审慎甄别。
平台声明:文章内容(如有图片或视频亦包括在内)由作者上传并发布,文章内容仅代表作者本人观点,简书系信息发布平台,仅提供信息存储服务。

相关阅读更多精彩内容

友情链接更多精彩内容