1.相关概念说明
1.1DMA介绍
DMA,英文全称是 Direct Memory Access,即直接内存访问。DMA 本质上是一块主板上独立的芯片,允许外设设备和内存存储器之间直接进行 IO 数据传输,其过程不需要 CPU 的参与。
1.2内核空间和用户空间介绍
为什么要分成内核空间和用户空间?
为了避免用户进程直接操作内核,保证内核安全,操作系统将虚拟内存划分为两部分,一部分是内核空间(Kernel-space),一部分是用户空间(User-space)。
用户空间:当启动某个应用程序时,操作系统会给应用程序分配一个单独的用户空间,其实就是一个用户独享的虚拟内存,每个用户进程之间的用户空间是完全隔离的、不共享的,当用户进程结束的时候,用户空间的虚拟内存也会随之释放。用户空间的权限较低,应用程序不能直接访问硬件资源和执行某些关键操作,因为这些操作可能会影响系统的稳定性和安全性。
内核空间:内核空间是操作系统的核心部分,它负责管理系统资源,包括CPU、内存、硬盘等,以及处理各种硬件设备的请求。内核空间拥有最高的权限,可以直接访问所有的硬件资源和执行任何操作。
当应用程序需要执行系统调用时,会从用户态切换到内核态,执行完毕后再切换回用户态。操作系统通过这种设计,确保了系统的稳定性和安全性,同时也为应用程序提供了一个相对安全和隔离的运行环境。
2.零拷贝
零拷贝并不是完全没有拷贝数据,而是减少用户态/内核态的切换次数以及CPU拷贝的次数。它通过减少或消除数据在内核空间和用户空间之间的拷贝操作,直接将数据从输入/输出设备传输到应用程序的内存空间,提高数据传输效率和性能。
3.实现方式
3.1mmap
mmap 内存映射的拷贝,指的是将用户空间的缓冲区和内核缓冲区进行映射处理,省略了数据在内核缓冲区和用户缓冲区之间的 CPU 拷贝,进而加快资源拷贝效率。
整个拷贝过程,可以用如下流程图来描述!
mmap 内存映射拷贝流程,从上图可以得出如下结论:
- 数据拷贝次数:2 次 DMA 拷贝,1 次 CPU 拷贝
- CPU 切换次数:4 次用户态和内核态的切换
整个过程省掉了数据在内核缓冲区和用户缓冲区之间的 CPU 拷贝环节,在实际的应用中,对资源的拷贝能提升不少。
3.2Linux系统的sendfile拷贝流程
在 Linux 2.1 内核版本中,引入了一个系统调用方法:sendfile。
当调用 sendfile() 时,DMA 将磁盘数据复制到内核缓冲区 kernel buffer;然后将内核中的 kernel buffer 直接拷贝到 socket buffer;最后利用 DMA 将 socket buffer 通过网卡传输给客户端。
整个拷贝过程,可以用如下流程图来描述!
在 Linux 2.4 内核版本中,对 sendfile 系统方法做了优化升级,引入 SG-DMA 技术,需要 DMA 控制器支持。
其实就是对 DMA 拷贝加入了 scatter/gather 操作,它可以直接从内核空间缓冲区中将数据读取到网卡。使用这个特点来实现数据拷贝,可以多省去一次 CPU 拷贝。
catter/Gather技术是一种数据传输机制,它允许数据从一个或多个非连续的内存区域(scatter)传输到另一个或多个非连续的内存区域(gather),而不需要CPU介入处理这些非连续的内存区域的数据拷贝。这项技术在DMA(Direct Memory Access)操作中尤为重要,可以显著提高数据传输效率。
- Scatter:指从通道中读取数据分散到多个缓冲区Buffer的过程,会将每个缓存区填满,直至通道中无数据或缓冲区没有空间。
- Gather:指将多个缓冲区Buffer聚集起来写入到通道的过程,类似于将多个缓冲区的内容连接起来写入通道
整个拷贝过程,可以用如下流程图来描述!
可以发现,sendfile With DMA scatter/gather 实现的拷贝,其中 2 次数据拷贝都是 DMA 拷贝,全程都没有通过 CPU 来拷贝数据,所有的数据都是通过 DMA 来进行传输的,这就是操作系统真正意义上的零拷贝(Zero-copy) 技术,相比其他拷贝方式,传输效率最佳。
4.总结
从上面的内容总结可以看出,所谓的零拷贝,其目的并不是说不需要拷贝数据,而是通过一些手段省略 CPU 拷贝环节,减少了不必要的拷贝次数,提升数据拷贝效率。
以 Linux 操作系统为例,真正意义上大家比较认可的零拷贝主要有 sendfile、splice 等方法,它们完全通过 DMA 控制器来实现数据的拷贝,无需 CPU 来参与数据拷贝的过程,这个过程被称为零拷贝。