零拷贝详解

news2024/10/7 2:25:48

目录

一、什么是零拷贝

二、传统的IO执行流程

三、零拷贝相关的知识点回顾

1、内核空间&用户空间

2、用户态&内核态

3、上下文切换

4、虚拟内存

5、DMA技术

四、零拷贝实现的几种方式

1、mmap+write实现的零拷贝

2、sendfile实现的零拷贝

3、sendfile+DMA scatter/gather实现的零拷贝

五、java提供的零拷贝方式

1、Java NIO对mmap的支持

2、Java NIO对sendfile的支持


一、什么是零拷贝

零拷贝字面上的意思包括两个,“零”和“拷贝”:

  • “拷贝”:就是指数据从一个存储区域转移到另一个存储区域。
  • “零” :表示次数为0,它表示拷贝数据的次数为0。

零拷贝指在进行数据 IO 时,数据在用户态下经历了零次 CPU 拷贝,并非不拷贝数据。通过减少数据传输过程中 内核缓冲区和用户进程缓冲区 间不必要的CPU数据拷贝 与 用户态和内核态的上下文切换次数,降低 CPU 在这两方面的开销,释放 CPU 执行其他任务,更有效的利用系统资源,提高传输效率,同时还减少了内存的占用,也提升应用程序的性能。

        由于零拷贝在内核空间中完成所有的内存拷贝,可以最大化使用 socket 缓冲区的可用空间,从而提高了一次系统调用中处理的数据量,进一步降低了上下文切换次数。零拷贝技术基于 PageCache,而 PageCache 缓存了最近访问过的数据,提升了访问缓存数据的性能,同时,为了解决机械磁盘寻址慢的问题,它还协助 IO 调度算法实现了 IO 合并与预读(这也是顺序读比随机读性能好的原因),这进一步提升了零拷贝的性能。

二、传统的IO执行流程

传统的IO流程,包括read和write的过程。

  • read:把数据从磁盘读取到内核缓冲区,再拷贝到用户缓冲区
  • write:先把数据写入到socket缓冲区,最后写入网卡设备。

  • 用户应用进程调用read函数,向操作系统发起IO调用,上下文从用户态转为内核态(切换1)
  • DMA控制器把数据从磁盘中,读取到内核缓冲区。
  • CPU把内核缓冲区数据,拷贝到用户应用缓冲区,上下文从内核态转为用户态(切换2),read函数返回
  • 用户应用进程通过write函数,发起IO调用,上下文从用户态转为内核态(切换3)
  • CPU将用户缓冲区中的数据,拷贝到socket缓冲区
  • DMA控制器把数据从socket缓冲区,拷贝到网卡设备,上下文从内核态切换回用户态(切换4),write函数返回

从流程图可以看出,传统IO的读写流程,包括了4次上下文切换(4次用户态和内核态的切换),4次数据拷贝(两次CPU拷贝以及两次的DMA拷贝)

三、零拷贝相关的知识点回顾

1、内核空间&用户空间

我们电脑上跑着的应用程序,其实是需要经过操作系统,才能做一些特殊操作,如磁盘文件读写、内存的读写等等。因为这些都是比较危险的操作,不可以由应用程序乱来,只能交给底层操作系统来。

因此,操作系统为每个进程都分配了内存空间,一部分是用户空间,一部分是内核空间。内核空间是操作系统内核访问的区域,是受保护的内存空间,而用户空间是用户应用程序访问的内存区域。 以32位操作系统为例,它会为每一个进程都分配了4G(2的32次方)的内存空间。

  • 内核空间:主要提供进程调度、内存分配、连接硬件资源等功能
  • 用户空间:提供给各个程序进程的空间,它不具有访问内核空间资源的权限,如果应用程序需要使用到内核空间的资源,则需要通过系统调用来完成。进程从用户空间切换到内核空间,完成相关操作后,再从内核空间切换回用户空间。

2、用户态&内核态

  • 如果进程运行于内核空间,被称为进程的内核态
  • 如果进程运行于用户空间,被称为进程的用户态。

3、上下文切换

  • 什么是CPU上下文?

CPU 寄存器,是CPU内置的容量小、但速度极快的内存。而程序计数器,则是用来存储 CPU 正在执行的指令位置、或者即将执行的下一条指令位置。它们都是 CPU 在运行任何任务前,必须的依赖环境,因此叫做CPU上下文。

  • 什么是CPU上下文切换?

它是指,先把前一个任务的CPU上下文(也就是CPU寄存器和程序计数器)保存起来,然后加载新任务的上下文到这些寄存器和程序计数器,最后再跳转到程序计数器所指的新位置,运行新任务。

一般我们说的上下文切换,就是指内核(操作系统的核心)在CPU上对进程或者线程进行切换。进程从用户态到内核态的转变,需要通过系统调用来完成。系统调用的过程,会发生CPU上下文的切换。

CPU 寄存器里原来用户态的指令位置,需要先保存起来。接着,为了执行内核态代码,CPU 寄存器需要更新为内核态指令的新位置。最后才是跳转到内核态运行内核任务。

 

4、虚拟内存

现代操作系统使用虚拟内存,即虚拟地址取代物理地址,使用虚拟内存可以有2个好处:

  • 虚拟内存空间可以远远大于物理内存空间
  • 多个虚拟内存可以指向同一个物理地址

正是多个虚拟内存可以指向同一个物理地址,可以把内核空间和用户空间的虚拟地址映射到同一个物理地址,这样的话,就可以减少IO的数据拷贝次数啦,示意图如下

5、DMA技术

DMA,英文全称是Direct Memory Access,即直接内存访问。DMA本质上是一块主板上独立的芯片,允许外设设备和内存存储器之间直接进行IO数据传输,其过程不需要CPU的参与

我们一起来看下IO流程,DMA帮忙做了什么事情

  • 用户应用进程调用read函数,向操作系统发起IO调用,进入阻塞状态,等待数据返回。
  • CPU收到指令后,对DMA控制器发起指令调度。
  • DMA收到IO请求后,将请求发送给磁盘;
  • 磁盘将数据放入磁盘控制缓冲区,并通知DMA
  • DMA将数据从磁盘控制器缓冲区拷贝到内核缓冲区。
  • DMA向CPU发出数据读完的信号,把工作交换给CPU,由CPU负责将数据从内核缓冲区拷贝到用户缓冲区。
  • 用户应用进程由内核态切换回用户态,解除阻塞状态

可以发现,DMA做的事情很清晰啦,它主要就是帮忙CPU转发一下IO请求,以及拷贝数据。为什么需要它的?

主要就是效率,它帮忙CPU做事情,这时候,CPU就可以闲下来去做别的事情,提高了CPU的利用效率。大白话解释就是,CPU老哥太忙太累啦,所以他找了个小弟(名叫DMA) ,替他完成一部分的拷贝工作,这样CPU老哥就能着手去做其他事情。

四、零拷贝实现的几种方式

零拷贝并不是没有拷贝数据,而是减少用户态/内核态的切换次数以及CPU拷贝的次数。零拷贝实现有多种方式,分别是

  • mmap+write
  • sendfile
  • 带有DMA收集拷贝功能的sendfile

1、mmap+write实现的零拷贝

前面介绍了虚拟内存,可以把内核空间和用户空间的虚拟地址映射到同一个物理地址,从而减少数据拷贝次数!mmap就是用了虚拟内存这个特点,它将内核中的读缓冲区与用户空间的缓冲区进行映射,所有的IO都在内核中完成。

mmap+write实现的零拷贝流程如下:

  • 用户进程通过mmap方法向操作系统内核发起IO调用,上下文从用户态切换为内核态。
  • CPU利用DMA控制器,把数据从硬盘中拷贝到内核缓冲区。
  • 上下文从内核态切换回用户态,mmap方法返回。
  • 用户进程通过write方法向操作系统内核发起IO调用,上下文从用户态切换为内核态。
  • CPU将内核缓冲区的数据拷贝到的socket缓冲区。
  • CPU利用DMA控制器,把数据从socket缓冲区拷贝到网卡,上下文从内核态切换回用户态,write调用返回。 

可以发现,mmap+write实现的零拷贝,I/O发生了4次用户空间与内核空间的上下文切换,以及3次数据拷贝。其中3次数据拷贝中,包括了2次DMA拷贝和1次CPU拷贝

mmap是将读缓冲区的地址和用户缓冲区的地址进行映射,内核缓冲区和应用缓冲区共享,所以节省了一次CPU拷贝‘’并且用户进程内存是虚拟的,只是映射到内核的读缓冲区,可以节省一半的内存空间

2、sendfile实现的零拷贝

sendfile是Linux2.1内核版本后引入的一个系统调用函数

sendfile表示在两个文件描述符之间传输数据,它是在操作系统内核中操作的,避免了数据从内核缓冲区和用户缓冲区之间的拷贝操作,因此可以使用它来实现零拷贝。

sendfile实现的零拷贝流程如下:

  1. 用户进程发起sendfile系统调用,上下文(切换1)从用户态转向内核态
  2. DMA控制器,把数据从硬盘中拷贝到内核缓冲区。
  3. CPU将读缓冲区中数据拷贝到socket缓冲区
  4. DMA控制器,异步把数据从socket缓冲区拷贝到网卡,
  5. 上下文(切换2)从内核态切换回用户态,sendfile调用返回。

 可以发现,sendfile实现的零拷贝,I/O发生了2次用户空间与内核空间的上下文切换,以及3次数据拷贝。其中3次数据拷贝中,包括了2次DMA拷贝和1次CPU拷贝。那能不能把CPU拷贝的次数减少到0次呢?有的,即带有DMA收集拷贝功能的sendfile!

3、sendfile+DMA scatter/gather实现的零拷贝

linux 2.4版本之后,对sendfile做了优化升级,引入SG-DMA技术,其实就是对DMA拷贝加入了scatter/gather操作,它可以直接从内核空间缓冲区中将数据读取到网卡。使用这个特点搞零拷贝,即还可以多省去一次CPU拷贝

sendfile+DMA scatter/gather实现的零拷贝流程如下:

  1. 用户进程发起sendfile系统调用,上下文(切换1)从用户态转向内核态
  2. DMA控制器,把数据从硬盘中拷贝到内核缓冲区。
  3. CPU把内核缓冲区中的文件描述符信息(包括内核缓冲区的内存地址和偏移量)发送到socket缓冲区
  4. DMA控制器根据文件描述符信息,直接把数据从内核缓冲区拷贝到网卡
  5. 上下文(切换2)从内核态切换回用户态,sendfile调用返回。

可以发现,sendfile+DMA scatter/gather实现的零拷贝,I/O发生了2次用户空间与内核空间的上下文切换,以及2次数据拷贝。其中2次数据拷贝都是包DMA拷贝。这就是真正的 零拷贝(Zero-copy) 技术,全程都没有通过CPU来搬运数据,所有的数据都是通过DMA来进行传输的。

五、java提供的零拷贝方式

1、Java NIO对mmap的支持

Java NIO有一个MappedByteBuffer的类,可以用来实现内存映射。它的底层是调用了Linux内核的mmap的API。

public class MmapTest { public static void main(String[] args) { try {
            FileChannel readChannel = FileChannel.open(Paths.get("./jay.txt"), StandardOpenOption.READ);
            MappedByteBuffer data = readChannel.map(FileChannel.MapMode.READ_ONLY, 0, 1024 * 1024 * 40);
            FileChannel writeChannel = FileChannel.open(Paths.get("./siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); //数据传输 writeChannel.write(data);
            readChannel.close();
            writeChannel.close();
        }catch (Exception e){
            System.out.println(e.getMessage());
        }
    }
}

2、Java NIO对sendfile的支持

FileChannel的transferTo()/transferFrom(),底层就是sendfile() 系统调用函数。Kafka 这个开源项目就用到它,平时面试的时候,回答面试官为什么这么快,就可以提到零拷贝sendfile这个点。

public class SendFileTest { public static void main(String[] args) { try {
            FileChannel readChannel = FileChannel.open(Paths.get("./jay.txt"), StandardOpenOption.READ); long len = readChannel.size(); long position = readChannel.position();
            
            FileChannel writeChannel = FileChannel.open(Paths.get("./siting.txt"), StandardOpenOption.WRITE, StandardOpenOption.CREATE); //数据传输 readChannel.transferTo(position, len, writeChannel);
            readChannel.close();
            writeChannel.close();
        } catch (Exception e) {
            System.out.println(e.getMessage());
        }
    }
}

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/717971.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

MySQL原理探索——23 MySQL是怎么保证数据不丢的

今天这篇文章,我会继续介绍在业务高峰期临时提升性能的方法。从文章标题“MySQL 是怎么保证数据不丢的”,你就可以看出来,今天我介绍的方法,跟数据的可靠性有关。 在前面文章,我都着重介绍了 WAL 机制(你可…

ElementUI plus框架Table表格cell-style属性的使用

官方文档说明: 例:设置单元格文字居中 Object方式: function方式:

安全 --- http报文包详解及burp简单使用

HTTP HTTP(超文本传输协议)是今天所有web应用程序使用的通信协议。最初HTTP只是一个为了获取基本文本的静态资源而开发的简单协议,后来对其进行扩展和利用,使其发展为能够支持如今常见的复杂分布式应用程序。 (1&…

PADS-LAYOUT菜单及工具使用

目录 1菜单栏 1.1文件菜单 1.2编辑菜单 1.3查看菜单 1.4设置菜单 1.5工具菜单 1.6帮助菜单 2工具栏 2.1标准工具栏 2.2绘图工具栏 2.3设计工具栏 2.4尺寸标注工具栏 2.5ECO工具栏 3系统配置 3.1全局选项 3.2设计选项 3.3栅格和捕获选项 3.4显示选项 3.5布线选…

【UnityDOTS 六】预制实例化成Entity

预制实例化成Entity 前言 从Authoring模式中,如何通过预制件来实例化一个对应的Entity对象到DOTS系统中。 一、Authoring模式与Runtime模式 Authoring创作模式:即我们熟悉的方便操作的创建预制的模式 Runtime模式:运行模式,即在…

Three.js教程:网格模型

推荐:将 NSDT场景编辑器 加到你的3D工具链 工具集: NSDT简石数字孪生 网格模型(三角形概念) 本节课给大家演示网格模型Mesh渲染自定义几何体BufferGeometry的顶点坐标,通过这样一个例子帮助大家建立**三角形(面)**的概念 三角形(面) 网格模型Mesh其实…

Spring Boot 中的 XA 事务

Spring Boot 中的 XA 事务 在现代化的应用程序开发中,事务管理是一个重要的话题。事务管理可以确保数据的一致性和完整性,同时也可以避免数据丢失和冲突等问题。在分布式环境中,XA 事务是一种常用的事务管理方式。在本文中,我们将…

基于麦克风阵列模块I2s6路slot数字音频信号的ADSP/STM32F4处理

hezkz17进数字音频系统研究开发交流答疑 1麦克风阵列 2 ADAU1452 DSP 输入接口 3 PCM数据算法处理

uni-app获取节点的相关信息

获取单个节点: selectorQuery.select(selector) 在当前页面下选择第一个匹配选择器 selector 的节点,返回一个 NodesRef 对象实例,可以用于获取节点信息。 selector 说明: selector 类似于 CSS 的选择器,但仅支持下列…

Jenkins 参数化构建

目录 前言: 以下是Jenkins官方的介绍: 首先新建一个自由风格的job,然后勾选“This project is parameterized”,如下图: 勾选参数构建 choice parameterized: 选项: 使用参数:…

linux驱动struct file_operations`中设置`owner`成员变量。

在Linux内核中,struct file_operations结构体是用来定义一个文件操作的集合。该结构体中包含了一组函数指针,这些函数指针指向了与文件操作相关的函数,例如文件的打开、关闭、读写、定位等操作。同时,该结构体中还包含了一些元数据…

Opencv项目实战:00 专栏内容介绍

目录 Opencv项目实战专栏介绍: 01 文字检测OCR 02 角度探测器 03 扫描二维码&条形码 04 全景图片拼接 05 物体检测 06 文档扫描仪 07 人脸识别和考勤系统 08 Yolov3更高精度的检测物体 09 物体尺寸测量 10 面部特征提取及添加滤镜 11 使用Opencv高亮…

接近完美的监控系统—普罗米修斯

内容 隐藏 1.怎么采集监控数据? 2.采集的数据结构与指标类型 2.1 数据结构 2.2 指标类型 3.实例概念 4.数据可视化 5.应用前景 普罗米修斯(Prometheus)是一个SoundCloud公司开源的监控和告警系统。当年,由于SoundCloud公司生产了太多的服务&#…

ant vue 自定义首页菜单实现

如图,我把 views/dataScreening/DataScreening 页面,设置成首页,登录以后自动跳转到这个页面 实现代码: 文件:/src/config/router.config.js import { UserLayout, TabLayout, RouteView, BlankLayout, PageView } from @/components/layouts/*** 走菜单,走权限控制* @t…

【深度学习】AIGC ,ControlNet 论文,原理,训练,部署,实战,教程

论文:https://arxiv.53yu.com/pdf/2302.05543 代码:https://github.com/lllyasviel/ControlNet 得分几个博客完成这个事情的记录了,此篇是第一篇,摘录了一些论文内容。ControlNet 的原理极为朴实无华(对每个block添加…

c++ connect函数连接失败

bool Connect() {//初始化网络WSADATA wsadata;WSAStartup(MAKEWORD(2, 2), &wsadata);if (0 ! WSAStartup(MAKEWORD(2, 2), &wsadata))return false;if (LOBYTE(wsadata.wVersion) ! 2 ||HIBYTE(wsadata.wVersion) ! 2) {printf("请求协议版本失败!\n");ret…

Ghatgpt正式登录苹果手机应用商城,并支持Siri和快捷指令

根据最新信息,OpenAI 发布的 ChatGPT 官方 iOS 应用程序迎来了重大更新。该应用程序已经在上个月登陆了美国、英国、法国、德国和韩国等 App Store,并且成为该市场上最受欢迎的免费应用程序。 作为生产力类应用的领导者,该应用程序完全免费&a…

MYSQL执行一条SELECT语句的具体流程

昨天CSDN突然抽风 我一个ctrlz把整篇文章给撤掉了还不能复原 直接心态崩了不想写了 不过这部分果然还是很重要,还是写出来吧 流程图 这里面总共有两层结构Server层 储存引擎 Server 层负责建立连接、分析和执行 SQL。MySQL 大多数的核心功能模块都在这实现,主要包…

PF-Net点云补全解读

论文链接:https://arxiv.org/pdf/2003.00410.pdfhttps://arxiv.org/pdf/2003.00410.pdf PF-Net是一个点云补全模型,整体网络为生成对抗网络(Gan)构成,G网络负责生成缺失的数据,D网络负责鉴别G网络生…

为什么Unity使用AssetBundle热更的时候要剔除掉.mainfest文件

1)为什么Unity使用AssetBundle热更的时候要剔除掉.mainfest文件 ​2)Addressable热更,断点续传问题 3)在线性空间,使用后处理解决UI混合问题 这是第341篇UWA技术知识分享的推送,精选了UWA社区的热门话题&am…