精华内容
下载资源
问答
  • 零拷贝技术
    千次阅读
    2021-12-05 21:42:14

    零拷贝技术

    概述

    零拷贝技术指在计算机执行操作时,CPU不需要先将数据从一个内存区域复制到另一个内存区域,从而可以减少上下文切换以及CPU的拷贝时间。它的作用是在数据报从网络设备到用户程序空间传递的过程中,减少数据拷贝次数,减少系统调用,实现CPU的零参与,彻底消除CPU的负载。

    实现零拷贝用到的主要技术是DMA数据传输技术和内存区域映射技术

    • 零拷贝机制可以减少数据在内核缓冲区和用户进程缓冲区之间反复的I/O拷贝操作
    • 零拷贝机制可以减少用户进程地址空间之间因为上下文切换而带来的CPU开销

    物理内存和虚拟内存

    由于操作系统的进程之间是共享CPU和内存资源的,因此需要一套完整的内存管理机制防止内存泄漏。

    现代操作系统提供了一种对贮存的抽象概念,即是虚拟内存。虚拟内存为每个进程提供了一个一致的,私有的地址空间,它让每个进程产生了一种自己在独享主存的错觉

    物理内存

    物理内存是相对于虚拟内存而言的。物理内存指通过物理内存条而获得的内存空间

    虚拟内存

    虚拟内存是计算机系统内存管理的一种技术。它使得应用程序认为它拥有连续的可用的内存,而实际上,虚拟内存通常是被分割成多个物理内存碎片,还有部分暂时存储在外部磁盘存储器上,在需要时进行数据交换,加载到物理内存中来

    虚拟内存地址和用户进程紧密相关,一般来说不同进程里的同一个虚拟地址指向的物理地址是不一样的,每个进程所能使用的虚拟地址大小和CPU位数有关。实际上物理内存可能远远小于虚拟内存的大小,每个用户进程维护了一个单独的页表,虚拟内存和物理内存就是用过这个页表实现地址空间的映射的。

    用户进程申请并访问物理内存的过程

    1. 用户进程向操作系统发出内存申请请求

    2. 系统会检查进程的虚拟地址空间是否被用完,如果有剩余,给进程分配虚拟地址

    3. 系统为这块虚拟地址创建内存映射,并将其放到该进程的页表当中

    4. 系统返回虚拟地址给用户进程,用户进程开始访问该虚拟地址

    5. CPU根据虚拟地址在此进程的页表中找到相应的内存映射,但是这个内存映射没有和物理内存关联,于是产生缺页中断

    6. os受到缺页中断后,分配真正的物理内存并将它关联到了页表相应的内存映射。中断处理完成后CPU就可以访问内存了

      缺页中断并不是每次都会发生的,只有os觉得有必要延迟分配内存的时候才用得着,很多时候会在系统分配真正物理内存并和内存映射进行关联

    虚拟内存的优点

    • 地址空间:提供更大的地址空间,并且地址空间是连续的,使得程序编写,连接更加简单
    • 进程隔离:不同进程的虚拟地址之间没有关系,所以一个进程的操作不会对其他进程造成影响
    • 数据保护:每块虚拟内存都有相应的读写属性,这样就能保护程序的代码段不被修改,数据块不能被执行
    • 内存映射:有了虚拟内存之后,可以直接映射磁盘上的文件到虚拟地址空间
    • 共享内存
    • 物理内存管理

    内核空间和用户空间

    os的核心是内核,独立于普通的应用程序,可以访问受保护的内存空间,也有访问底层硬件设备的权限。为了避免用户进程直接操作内核,os讲虚拟内存划分为两部分,一部分是内核空间,一部分是用户空间。在Linux系统中,内核模块运行在内核空间,对应的进程处于内核态,而用户程序运行在用户空间,对应的进程处于用户态。

    内核空间

    内核空间总是驻留在内存中,它是为操作系统的内核保留的。应用程序是不允许直接在该区域进行读写或直接调用内核代码定义的函数的,按访问权限可以分为进程私有和进程共享:

    • 进程私有的虚拟内存:每个进程都有单独的内核栈,页表,task结构以及mem_map结构等
    • 进程共享的虚拟内存:属于所有进程共享的内存区域,包括物理存储器,内核数据和内核代码区域

    用户空间

    每个普通的用户进程都有一个单独的用户空间,处于用户态的进程不能访问内核空间中的数据,也不能直接调用内核函数的,因此要进行系统调用时,就要将进程切换到内核态。用户空间包括以下几个内存区域:

    • 运行时栈:每当一个函数被调用时,该函数的返回类型和一些调用的信息被存储到栈顶,调用结束后调用信息会被弹出并释放掉内存
    • 运行时堆:用于存放进程运行中被动态分配的内存段,位于BSS和栈中间的地址位。堆的效率要比栈低的多
    • 代码段:存放CPU可以执行的机器指令,该部分内存只能读不能写。通常代码区是共享的,其他执行程序可调用它
    • 未初始化的数据段:存放未初始化的全局变量
    • 已初始化的数据段:存放已初始化的全局变量,比如静态全局变量,静态局部变量和常量等
    • 内存映射区域:例如将动态库,共享内存等虚拟空间的内存映射到物理空间的内存

    Linux I/O读写方式

    Linux提供了轮询,I/O中断以及DMA传输这三种磁盘与主存之间的数据传输机制:

    1. 轮询:基于死循环堆I/O端口进行不断检测
    2. I/O中断方式:当数据到达时,磁盘主动向CPU发起中断请求,由CPU自身负责数据的传输过程
    3. DMA传输:在I/O终端的基础上引入DMA磁盘控制器,由DMA磁盘控制器负责数据的传输,降低了I/O终端操作对CPU资源的大量消耗

    I/O中断原理

    在DMA技术出现之前俺,应用程序域磁盘之间的I/O操作都是通过CPU中断完成的。每次用户进程读取磁盘数据时,都需要CPU中断,然后发起I/O请求等待数据读取和拷贝完成,每次的I/O中断都导致CPU的上下文切换

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-BtUqpfIh-1638711733230)(C:\Users\Leoyu\AppData\Roaming\Typora\typora-user-images\image-20211130215135794.png)]

    1. 用户进程向CPU发起read系统抵用读取数据,由用户态切换为内核态,然后一直阻塞等待数据的返回
    2. CPU在接收到指令以后对磁盘发起I/O请求,将磁盘数据先放入磁盘控制器缓冲区
    3. 数据准备完成以后,磁盘向CPU发起I/O中断
    4. CPU受到I/O中断以后将磁盘缓冲歌曲中的数据拷贝到内核缓冲区,再从内核缓冲区拷贝到用户缓冲区
    5. 用户进程切换回用户态,解除阻塞状态

    DMA传输

    DMA的全称叫做直接内存出去(Direct Memory Access),是一种允许外围设备直接访问系统主内存的机制。也就是说,基于DMA访问方式,系统主内存域硬盘或网卡之间的数据传输可以绕开CPU的全程调度。

    整个数据传输操作在一个DMA控制器的控制下进行的。CPU除了在数据传输开始和结束时做一点处理外,在传输过程中CPU可以继续进行其他的工作。这样在大部分时间里,CPU计算和I/O操作都处于并行操作,使整个计算机系统的效率大大提高

    1. 用户进程向CPU发起read系统调用读取数据,由用户态切换为内核态,然后一直阻塞等待数据的返回
    2. CPU在接收到指令以后对DMA磁盘控制器发起调度指令
    3. DMA磁盘控制器对磁盘发起I/O请求,将磁盘数据先放入磁盘控制器缓冲区,CPU全程不参与此过程
    4. 数据读取完成后,DMA磁盘控制器会接收到磁盘的通知,将数据从磁盘控制器缓冲区拷贝到内核缓冲区
    5. DMA磁盘控制器向CPU发送数据都玩的信号,由CPU负责将数据从内核缓冲区拷贝到用户缓冲区
    6. 用户进程由内核态切换回用户态,解除阻塞状态

    传统I/O操作

    传统的访问方式是通过write和read两个系统调用时显得,通过read函数读取文件到缓冲区中,然后通过write函数把缓存中的数据输出到网络端口

    read(file_fd, tmp_buf, len);
    write(socket_fd, tmp_buf, len);
    

    整个过程涉及2次CPU拷贝,2次DMA拷贝,以及4次上下文切换

    • 上下文切换:当用户程序向内核发起系统调用时,CPU将用户进程从用户态切换为内核态,当系统调用返回时,CPU将用户进程从内核态切换回用户态
    • CPU拷贝:由CPU直接处理数据的传送,数据拷贝时会一直占用CPU的资源
    • DMA拷贝:由CPU向DMA磁盘下达指令,让DMA控制器处理数据传送,传送完毕时把信息反馈给CPU,从而减轻CPU资源的占用率

    零拷贝方式(前面铺垫一大堆,终于是到重点了)

    零拷贝技术主要有三个实现思路:用户态直接I/O,减少数据拷贝次数以及写时复制技术

    • 用户态直接I/O:应用程序可以直接访问硬件存储,操作系统内核只是辅助数据传输。直接I/O不存在内核空间缓冲区和用户空间缓冲区之间的数据拷贝
    • 减少数据拷贝次数:在数据传输过程中,避免数据在用户空间缓冲区和系统内核空间缓冲区之间的CPU拷贝,以及数据在系统内核空间内的CPU拷贝,这也是当前的主流零拷贝技术的实现思路
    • 写时复制技术:写时复制指的是当多个进程共享同一块数据时,如果其中一个进程需要对这份数据进行修改,那么将其拷贝到自己的进程地址空间,如果只是数据读取则不需要进行拷贝

    用户态直接I/O

    这种方式绕过内核,极大提高了性能

    用户态直接I/O只能适用于不需要内核缓冲区处理的应用程序,这些应用程序通常在进程地址空间有自己的数据缓存机制,由于CPU和磁盘I/O之间的执行时间差距,会造成大量资源的浪费,解决方案是配合异步I/O使用

    mmap+write

    使用mmap+write代替原来的read+write方式,减少了1次CPU拷贝操作。mmap是Linux提供的一种内存映射文件方法,即将一个进程的地址空间中的一段虚拟地址映射到磁盘文件地址

    tmp_buf = mmap(file_fd, len);
    write(socket_fd, tmp_buf, len);
    

    使用mmap的目的是将内核中读缓冲区的地址与用户空间的缓冲区进行映射,从而实现内核缓冲区与应用陈鼓内存的共享,省去了将数据从内核读缓冲区拷贝到用户缓冲区的过程,内核读缓冲区仍需将数据到内核写缓冲区

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-qlYjcY5R-1638711733234)(C:\Users\Leoyu\AppData\Roaming\Typora\typora-user-images\image-20211201000703550.png)]

    基于mmap+write的零拷贝方式,整个拷贝过程会发生4次上下文切换,1次CPU拷贝和2次DMA拷贝

    1. 用户进程通过mmap函数向内核发起系统调用,上下文从用户态切换为内核态
    2. 将用户进程的内核空间的读缓冲区与用户空间的缓存区进行内存地址映射
    3. CPU利用DMA控制器将数据从主存或硬盘拷贝到内核空间的读缓冲区(read buffer)
    4. 上下文从内核态切换回用户态,mmap系统调用执行返回
    5. 用户进程通过write函数向内核发起系统调用,上下文从用户态切换为内核态
    6. CPU将读缓冲区中的数据拷贝到的网络缓冲区(socket buffer)
    7. CPU利用DMA控制器将数据从网络缓冲区拷贝到网卡进行数据传输
    8. 上下文奇幻会用户态,write系统调用执行返回

    mmap主要是提高I/O性能,虽然减少了1次拷贝,但是如果mmap一个文件被另一个进程所截获,那么write系统调用会因为访问非法地址被SIGBUS信号终止,SIGBUS会杀死进程,服务器可能会因此被终止

    sendfile

    sendfile系统调用在Linux内核版本2.1中被引入,目的是简化通过网络在两个通道之间进行的数据传输过程。sendfile不仅减少了CPU拷贝的次数,还减少了上下文切换的次数

    sendfile(socket_fd, file_fd, len);
    

    通过sendfile系统调用,数据可以直接在内核空间内部进行I/O传输,从而省去了数据在用户空间和内核空间之间的来回拷贝,但是对用户空间是完全不可见

    基于sendfile的零拷贝方式过程会发生2次上下文切换,1次CPU拷贝和2次DMA拷贝:

    1. 用户进程通过sendfile函数向内核发起系统调用,上下文从用户态切换为内核态
    2. CPU利用DMA控制器将数据从主存或硬盘拷贝到内核空间的读缓冲区
    3. CPU将读缓冲区的数据拷贝到网络缓冲区
    4. CPU利用DMA控制器将数据从网络缓冲区拷贝到网卡进行数据传输
    5. 上下文切换回用户态,sendfile系统调用返回

    sendfile存在的问题是用户程序不能对数据进行修改,只是单纯地完成了一次数据传输过程

    sendfile+DMA gather copy

    Linux 2.4版本的内核对sendfile系统调用进行修改,为DMA拷贝引入了gather操作。它将内核空间的读缓冲区中对应的数据描述信息记录到相应的网络缓冲区中,由DMA根据内存地址,地址偏移量将数据批量地从读缓冲区拷贝到网卡设备中,这样就省去了内核空间中仅剩的1次CPU拷贝操作

    sendfile(socket_fd, file_fd, len);
    

    在硬件的支持下,sendfile 拷贝方式不再从内核缓冲区的数据拷贝到 socket 缓冲区,取而代之的仅仅是缓冲区文件描述符和数据长度的拷贝,这样 DMA 引擎直接利用 gather 操作将页缓存中数据打包发送到网络中即可,本质就是和虚拟内存映射的思路类似。

    基于sendfile+DMA gather copy系统调用的零拷贝方式,整个过程会发生2次上下文切换,0次CPU拷贝以及2次DMA拷贝

    1. 用户进程通过sendfile函数向内核发起系统调用,上下文切换为内核态
    2. CPU利用DMA控制器将数据从主存或硬盘拷贝到内核空间的读缓冲区
    3. CPU将读缓冲区的文件描述符和数据长度拷贝到网络缓冲区
    4. 基于文件描述符和数据长度,CPU利用DMA控制器的gather/scatter操作直接批量地将数据从内核的读缓冲区拷贝到网卡进行数据传输
    5. 上下文切换回用户态,sendfile系统调用执行返回

    sendfile+DMA gather copy只适用于将数据从文件拷贝到socket套接字上

    splice

    Linux 在 2.6.17 版本引入 splice 系统调用,不仅不需要硬件支持,还实现了两个文件描述符之间的数据零拷贝。

    splice(fd_in, off_in, fd_out, off_out, len, flags);
    

    splice系统调用可以在内核空间的读缓冲区和网络缓冲区之间建立管道,从而避免了两者之间的CPU拷贝操作

    [外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-odtI1T7l-1638711733236)(C:\Users\Leoyu\AppData\Roaming\Typora\typora-user-images\image-20211201004623176.png)]

    基于splice系统调用的零拷贝方式,整个拷贝过程会发生2

    次上下文切换,0次CPU拷贝以及2次DMA拷贝:

    1. 用户进程通过splice函数向内核发起系统调用,上下文切换为内核态
    2. CPU利用DMA控制器将数据从主存或硬盘拷贝至内核的读缓冲区
    3. CPU在内核的读缓冲区和网络缓冲区之间建立起管道
    4. CPU利用DMA控制器将数据从网络缓冲区拷贝至网卡进行数据传输
    5. 上下文切换回用户态,splice系统调用执行返回

    splice 拷贝方式也同样存在用户程序不能对数据进行修改的问题。除此之外,它使用了 Linux 的管道缓冲机制,可以用于任意两个文件描述符中传输数据,但是它的两个文件描述符参数中有一个必须是管道设备。

    写时复制

    写时复制指的是当多个进程共享同一块数据时,如果其中一个进程需要对这份数据进行修改,那么就需要将其拷贝到自己的进程地址空间中。这样做并不影响其他进程对这块数据的操作,每个进程要修改的时候才会进行拷贝,所以叫写时复制

    缓冲区共享

    Solaris上实现的fbuf(fast Buffer)

    fbuf的思想是每个进程都维护着一个缓冲区池,这个缓冲区能被同时映射到用户空间和内核态,内核和用户共享这个缓冲区池

    Linux零拷贝对比

    无论是传统 I/O 拷贝方式还是引入零拷贝的方式,2 次 DMA Copy 是都少不了的,因为两次 DMA 都是依赖硬件完成的。下面从 CPU 拷贝次数、DMA 拷贝次数以及系统调用几个方面总结一下上述几种 I/O 拷贝方式的差别。

    拷贝方式CPU拷贝DMA拷贝系统调用上下文切换
    传统方式(read + write)22read / write4
    内存映射(mmap + write)12mmap / write4
    sendfile12sendfile2
    sendfile + DMA gather copy02sendfile2
    splice02splice2

    Java NIO零拷贝实现

    在Java NIO中的通道(Channel)就相当于操作系统的内核空间的缓冲区,而缓冲区对应的相当于操作系统的用户空间中的用户缓冲区

    • 通道是全双工通信的,既可能是读缓冲区,也可能是网络缓冲区
    • 缓冲区分为堆内存和堆外内存,这是通过malloc()分配出来的用户态内存

    堆外内存(DirectBuffer)在使用后需要应用程序手动回收,而堆内存(HeapBuffer)的数据在GC时可能会被自动回收。因此,在使用HeapBuffer读写数据时,为了避免缓冲区数据因为GC而丢失,NIO会先把HeapBuffer内部的数据拷贝到一个临时的DirectBuffer中的本地内存(native memory),这个拷贝涉及copyMemory()的调用,实现原理和memcpy()类似。最后将临时生成的DirectBuffer内部的数据的内存地址传给I/O调用函数,这样就避免了再去访问Java对象处理I/O读写

    MappedByteBuffer

    MappedByteBuffer是NIO基于内存映射(mmap)这种零拷贝方式的提供的一种实现,它继承自ByteBuffer。FileChannel定义了一个map()方法,它可以把一个文件从position位置开始的size大小区域映射为内存映像文件。

    public abstract MappedByteBuffer map(MapMode mode, long position, long size)
            throws IOException;
    
    • mode:限定内存映射区域对内存映像文件的访问模式,包括只可读,可读可写和写时拷贝三种模式
    • position:文件映射的起始地址,对应内存映射区域的首地址
    • size:文件映射的字节长度,从position往后的字节数,对应内存映射区域的大小

    RocketMQ和Kafka对比

    RocketMQ 选择了 mmap + write 这种零拷贝方式,适用于业务级消息这种小块文件的数据持久化和传输;而 Kafka 采用的是 sendfile 这种零拷贝方式,适用于系统日志消息这种高吞吐量的大块文件的数据持久化和传输。但是值得注意的一点是,Kafka 的索引文件使用的是 mmap + write 方式,数据文件使用的是 sendfile 方式。

    消息队列零拷贝方式优点缺点
    RocketMQmmap + write适用于小块文件传输,频繁调用时,效率很高不能很好的利用 DMA 方式,会比 sendfile 多消耗 CPU,内存安全性控制复杂,需要避免 JVM Crash 问题
    Kafkasendfile可以利用 DMA 方式,消耗 CPU 较少,大块文件传输效率高,无内存安全性问题小块文件效率低于 mmap 方式,只能是 BIO 方式传输,不能使用 NIO 方式
    更多相关内容
  • MySQL零拷贝技术详解
  • 零拷贝技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。 原始的网络请求,需要数次在用户态和内核态之间切换以及数据的...

    前言

    零拷贝技术是指计算机执行操作时,CPU不需要先将数据从某处内存复制到另一个特定区域。这种技术通常用于通过网络传输文件时节省CPU周期和内存带宽。

    原始的网络请求,需要数次在用户态和内核态之间切换以及数据的拷贝,这无疑大大影响了处理的效率,零拷贝技术就是为解决这一问题而诞生的。

    我们常见的高性能组件(Netty、Kafka等),其内部基本都应用了零拷贝,在学习这些组件之前,有必要先了解什么是零拷贝。

    推荐视频:

    C++架构师学习地址:C/C++Linux服务器开发高级架构师/Linux后台架构师

    零拷贝的实现,用户态协议栈ntytcp

    手写用户态协议栈,udpipeth数据包的封装,零拷贝的实现,柔性数组

    传统文件传输 read + write

    DMA拷贝:指外部设备不通过CPU而直接与系统内存交换数据的接口技术

    如上图所示,传统的网络传输,需要进行4次用户态和内核态切换,4次数据拷贝(2次CPU拷贝,2次DMA拷贝)

    上下文的切换涉及到操作系统,相对CPU速度是非常耗时的,而且仅仅一次文件传输,竟然需要4次数据拷贝,造成CPU资源极大的浪费

    不难看出,传统网络传输涉及很多冗余且无意义的操作,导致应用在高并发情况下,性能指数级下降,表现异常糟糕

    为了解决这一问题,零拷贝技术诞生了,他其实是一个抽象的概念,但其本质就是通过减少上下文切换和数据拷贝次数来实现的

    mmap + write

    如上图所示,mmap技术传输文件,需要进行4次用户态和内核态切换,3次数据拷贝(1次CPU拷贝、两次DMA拷贝)

    相对于传统数据传输,mmap减少了一次CPU拷贝,其具体过程如下:

    1. 应用进程调用 mmap() ,DMA 会把磁盘的数据拷贝到内核的缓冲区里,应用进程跟操作系统内核「共享」这个缓冲区
    2. 应用进程再调用 write(),操作系统直接将内核缓冲区的数据拷贝到 socket 缓冲区中,这一切都发生在内核态,由 CPU 来搬运数据
    3. 最后,把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程是由 DMA 搬运的

    显然仅仅减少一次数据拷贝,依然难以满足要求

    sendfile

    如上图所属,sendfile技术传输文件,需要进行2次用户态和内核态的切换,3次数据拷贝(1次CPU拷贝、两次DMA拷贝)

    相对于mmap,其又减少了两次上下文的切换,具体过程如下:

    1. 应用调用sendfile接口,传入文件描述符,应用程序切换至内核态,并通过 DMA 将磁盘上的数据拷贝到内核缓冲区中
    2. CPU将缓冲区数据拷贝至Socket缓冲区
    3. DMA将数据拷贝到网卡的缓冲区里,应用程序切换至用户态

    sendfile其实是将原来的两步读写操作进行了合并,从而减少了2次上下文的切换,但其仍然不是真正意义上的“零”拷贝

    文章福利:现在C++程序员面临的竞争压力越来越大。那么,作为一名C++程序员,怎样努力才能快速成长为一名高级的程序员或者架构师,或者说一名优秀的高级工程师或架构师应该有怎样的技术知识体系,这不仅是一个刚刚踏入职场的初级程序员,也是工作三五年之后开始迷茫的老程序员,都必须要面对和想明白的问题。为了帮助大家少走弯路,技术要做到知其然还要知其所以然。以下视频获取点击C++架构师学习资料

    如果想学习C++工程化、高性能及分布式、深入浅出。性能调优、TCP,协程,Nginx源码分析Nginx,ZeroMQ,MySQL,Redis,MongoDB,ZK,Linux内核,P2P,K8S,Docker,TCP/IP,协程,DPDK的朋友可以看一下这个学习地址:C/C++Linux服务器开发高级架构师/Linux后台架构师icon-default.png?t=L892https://ke.qq.com/course/417774?flowToken=1013189

    sendfile + SG-DMA

    从 Linux 内核 2.4 版本开始起,对于支持网卡支持 SG-DMA 技术的情况下, sendfile() 系统调用的过程发生了点变化,如上图所示,sendfile + SG-DMA技术传输文件,需要进行2次用户态和内核态的切换,2次数据拷贝(1次DMA拷贝,1次SG-DMA拷贝)

    具体过程如下:

    1. 通过 DMA 将磁盘上的数据拷贝到内核缓冲区里;
    2. 缓冲区描述符和数据长度传到 socket 缓冲区,这样网卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里,此过程不需要将数据从操作系统内核缓冲区拷贝到 socket 缓冲区中,这样就减少了一次数据拷贝;

    此种方式对比之前的,真正意义上去除了CPU拷贝,CPU 的高速缓存再不会被污染了,CPU 可以去执行其他的业务计算任务,同时和 DMA 的 I/O 任务并行,极大地提升系统性能。

    但他的劣势也很明显,强依赖于硬件的支持

    splice

    Linux 在 2.6.17 版本引入 splice 系统调用,不再需要硬件支持,同时还实现了两个文件描述符之间的数据零拷贝。

    splice 系统调用可以在内核空间的读缓冲区(read buffer)和网络缓冲区(socket buffer)之间建立管道(pipeline),从而避免了用户缓冲区和Socket缓冲区的 CPU 拷贝操作。

    基于 splice 系统调用的零拷贝方式,整个拷贝过程会发生 2次用户态和内核态的切换,2次数据拷贝(2次DMA拷贝),具体过程如下:

    1. 用户进程通过 splice() 函数向内核(kernel)发起系统调用,上下文从用户态(user space)切换为内核态(kernel space)。
    2. CPU 利用 DMA 控制器将数据从主存或硬盘拷贝到内核空间(kernel space)的读缓冲区(read buffer)。
    3. CPU 在内核空间的读缓冲区(read buffer)和网络缓冲区(socket buffer)之间建立管道(pipeline)。
    4. CPU 利用 DMA 控制器将数据从网络缓冲区(socket buffer)拷贝到网卡进行数据传输。
    5. 上下文从内核态(kernel space)切换回用户态(user space),splice 系统调用执行返回。

    splice 拷贝方式也同样存在用户程序不能对数据进行修改的问题。除此之外,它使用了 Linux 的管道缓冲机制,可以用于任意两个文件描述符中传输数据,但是它的两个文件描述符参数中有一个必须是管道设备

    总结

    本文简单介绍了 Linux 中的几种 Zero-copy 技术,随着技术的不断发展,又出现了诸如:写时复制、共享缓冲等技术,本文就不再赘述。

    广义的来讲,Linux 的 Zero-copy 技术可以归纳成以下三大类:

    • 减少甚至避免用户空间和内核空间之间的数据拷贝:在一些场景下,用户进程在数据传输过程中并不需要对数据进行访问和处理,那么数据在 Linux 的 Page Cache 和用户进程的缓冲区之间的传输就完全可以避免,让数据拷贝完全在内核里进行,甚至可以通过更巧妙的方式避免在内核里的数据拷贝。这一类实现一般是是通过增加新的系统调用来完成的,比如 Linux 中的 mmap(),sendfile() 以及 splice() 等。
    • 绕过内核的直接 I/O:允许在用户态进程绕过内核直接和硬件进行数据传输,内核在传输过程中只负责一些管理和辅助的工作。这种方式其实和第一种有点类似,也是试图避免用户空间和内核空间之间的数据传输,只是第一种方式是把数据传输过程放在内核态完成,而这种方式则是直接绕过内核和硬件通信,效果类似但原理完全不同。
    • 内核缓冲区和用户缓冲区之间的传输优化:这种方式侧重于在用户进程的缓冲区和操作系统的页缓存之间的 CPU 拷贝的优化。这种方法延续了以往那种传统的通信方式,但更灵活。
    展开全文
  • 主要介绍了浅析Linux中的零拷贝技术的使用,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要的朋友们下面随着小编来一起学习学习吧
  • 本文介绍了零拷贝技术的简单原理以及实现零拷贝技术的两种方式:sendfile & mmap ,希望能够帮助到大家

    零拷贝技术

    文章参考:

    知乎文章

    小林图解系统

    Linux高性能服务器编程

    零拷贝技术大体来说就是没有通过CPU在内存层面进行拷贝数据,而是通过DMA进行传输

    这样的提升是很大的,CPU就是应该让它用在关键的地方才行

    前提:

    Server将文件sendFile发送给客户端,那么传统的就是需要调用两个系统调用read & write

    read(sendFile, tmp_buf, len);						//从磁盘中读出来
    write(socket , tmp_buf, len);						//写到socket中去
    

    传统模式下:
    请添加图片描述

    上下文切换&数据拷贝

    我们使用了两个系统调用:readwrite, 发生了4次用户态内核态之间的切换

    4次数据之间的拷贝:

    • 将磁盘的数据拷贝到操作系统内核的缓存区(DMA)
    • 将内核缓冲区中的数据拷贝到用户的缓冲区中(CPU)
    • 将拷贝到用户缓冲区的数据拷贝到内核的socket缓冲区中(CPU)
    • 将内核的socket缓冲区数据拷贝到网卡的缓冲区中(DMA)

    sendfile实现零拷贝

    #include <sys/socket.h>
    ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
    		//目的端文件描述符、源文件描述符、源端偏移量、复制数据的长度
    		//返回值是实际复制的长度
    

    sendfile函数在两个文件描述符之间传递数据(完全在内核中操作),从而避免了内核缓冲区和用户缓冲区之间的数据拷贝,实现了零拷贝

    ⚠️:sendfile几乎是专门为在网络上传输文件而设计的,因为源端文件必须指向真实的文件,目的端文件必须指向socket,因此是专为网络而生的

    sendfile的模式
    请添加图片描述

    上下文切换&数据拷贝

    总共发生了两次用户态内核态之间的转换,减少了两次上下文切换

    数据之间的拷贝只有3次

    🌰:

    代码实现起来也是更加的精简,假设我们Server参数:ip port filename

    //......
    //创建socket,bind,listen,accept
    //filefd:待发送的文件名,connfd:Server套接字
    
    filefd(filename, O_RDONLY);			//打开文件
    struct stat stat_buf;
    fstat(filefd, &stat_buf);				//用于记录待发送文件状态
    
    //
    
    
    sendfile(connfd, filefd, NULL, stat_buf.st_size);		//直接发送到套接字,及其精简
    close(fd);
    
    
    
    
    //.....
    

    mmap + write实现零拷贝

    buf = mmap(file, len);
    write(sockfd, buf, len);
    

    mmap()系统调用函数会将 内核缓冲区中的数据 映射用户空间 ,这样就不用实现用户空间的拷贝了

    请添加图片描述

    这样也是减少了一次拷贝,但是同样还是需要4次上下文切换

    mmap传输大文件有优势,传输小文件可能出现碎片🧩

    展开全文
  • Linux中的零拷贝技术

    2020-09-28 16:39:29
    Linux中的零拷贝技术,对于开发使用linux内存管理的设计开发者来说,是一本好的参考书,可以指导用户进行高效零拷贝技术开发
  • 深入理解零拷贝技术.doc
  • 什么是“零拷贝技术 要想要了解“零拷贝”机制,首先要了解在什么地方会用到这个东西。试想一个场景:我们需要从磁盘读取一个文件,然后通过网络输出到一个客户端。 一般的文件传输过程 考虑这样一种常用的情形:...

    千里之行,始于足下

    什么是“零拷贝”技术

    要想要了解“零拷贝”机制,首先要了解在什么地方会用到这个东西。试想一个场景:我们需要从磁盘读取一个文件,然后通过网络输出到一个软件客户端。

    一般的文件传输过程

    考虑这样一种常用的情形:开发者需要将静态内容(类似图片、数据表、文件)发送给远程的用户。那么这个情形就意味着开发者需要先将静态内容从磁盘中拷贝出来放到一个内存buf中,然后将这个buf通过socket传输给用户,进而用户或者静态内容的展示。这看起来再正常不过了,但是实际上这是很低效的流程,我们把上面的这种情形抽象成下面的过程:

    read(file, tmp_buf, len);
    write(socket, tmp_buf, len);
    

    首先调用read将静态内容,这里假设为数据文件A,读取到tmp_buf, 然后调用write将tmp_buf写入到socket中,如图:
    在这里插入图片描述

    DMA :direct memory copy 直接内存拷贝(不使用CPU)

    在这个过程中数据文件A的经历了4次复制的过程:

    • 1 调用read方法以后,将数据文件A从磁盘拷贝到kernel(内核)buffer。
    • 2 CPU控制将kernel buffer内的数据复制到用户空间buffer。
    • 3 再将用户空间buffer里的内容复制到内核的socket buffer区。
    • 4 将内核的socket buffer区的内容复制给协议引擎(这里指网卡驱动)

    从上面,我们可以看到数据白白从kernel模式到user模式走了一圈,浪费了2次copy(第一次从kernel模式拷贝到user模式;第二次从user模式再拷贝回kernel模式,即上面4次过程的第2和3步骤)。而且上面的过程中kernel和user模式的上下文的切换也是4次。

    第1步数据从磁盘使用DMA拷贝到内存缓冲是必须的,需要系统读取数据给网卡嘛。但是为啥还要从内核复制一份到用户空间呢?应用程序直接使用内核缓冲区的数据不就行了吗?

    这是因为对于操作系统来说,可能有多个应用程序同时使用这些数据,并且有可能进行修改,如果大家都使用同一份内核的数据就会发生冲突,因此,就设计为每个应用程式在使用时就得先拷贝到自己的用户空间。但是这个机制在不需要做修改的场景就产生了浪费,数据本来可以呆在内核缓冲区不动,没必要再多此一举拷贝一次到用户空间

    为了避免这种浪费,人们一开始采用了mmap调用的方式来进行优化。即应用程序不再调用read,而是采用mmap,mmap会从磁盘复制数据到内核缓冲区,然后与用户进程共享该内核缓冲区这样就不再需要从内核缓冲区复制到用户缓冲区了,也就比之前少了一次数据复制过程。

    mmap内存映射

    例如,在 Linux 中,减少拷贝次数的一种方法是调用 mmap() 来代替调用 read,比如:

    tmp_buf=mmap(file,len);
    write(socket,tmp_buf,len);
    

    首先,应用程序调用了mmap()以后,数据会先通过DMA(直接存储器访问) 被复制到操作系统内核的缓冲区中去。

    接着,应用程序跟操作系统共享这个缓冲区,这样,操作系统内核和应用程序存储空间就不需要再进行任何的数据复制操作。应用程序调用了 write() 之后,操作系统内核将数据从原来的内核缓冲区中复制到与 socket 相关的内核缓冲区中。接下来,数据从内核 socket 缓冲区复制到协议引擎中去,这是第三次数据拷贝操作。如下图所示:

    在这里插入图片描述
    现在,你只需要从内核缓冲区拷贝到 Socket 缓冲区即可,这将减少一次内存拷贝(从 4 次变成了 3 次),但不减少上下文切换次数。

    虽然mmap这种方式减少了一次拷贝,但是,这种改进也是需要代价的。当对文件进行了内存映射,然后调用 write() 系统调用,如果此时其他的进程截断了这个文件,那么 write() 系统调用将会被总线错误信号 SIGBUS 中断,因为此时正在执行的是一个错误的存储访问。这个信号将会导致进程被杀死,解决这个问题可以通过以下这两种方法:

    1. 为 SIGBUS 安装一个新的信号处理器,这样,write() 系统调用在它被中断之前就返回已经写入的字节数目,errno 会被设置成 success。但是这种方法也有其缺点,它不能反映出产生这个问题的根源所在,因为 BIGBUS 信号只是显示某进程发生了一些很严重的错误。

    2. 是通过文件租借锁来解决这个问题的,这种方法相对来说更好一些。我们可以通过内核对文件加读或者写的租借锁,当另外一个进程尝试对用户正在进行传输的文件进行截断的时候,内核会发送给用户一个实时信号:RT_SIGNAL_LEASE 信号,这个信号会告诉用户内核破坏了用户加在那个文件上的写或者读租借锁,那么 write() 系统调用则会被中断,并且进程会被 SIGBUS 信号杀死,返回值则是中断前写的字节数,errno 也会被设置为 success。文件租借锁需要在对文件进行内存映射之前设置。

    使用 mmap 是 POSIX 兼容的,但是使用 mmap 并不一定能获得理想的数据传输性能。数据传输的过程中仍然需要一次 CPU 复制操作,而且映射操作也是一个开销很大的虚拟存储操作,这种操作需要通过更改页表以及冲刷 TLB (使得 TLB 的内容无效)来维持存储的一致性。但是,因为映射通常适用于较大范围,所以对于相同长度的数据来说,映射所带来的开销远远低于 CPU 拷贝所带来的开销。

    sendfile()

    为了简化用户接口,同时还要继续保留 mmap()/write() 技术的优点:减少 CPU 的复制次数,Linux 在版本 2.1 中引入了 sendfile() 这个系统调用。
    在这里插入图片描述
    sendfile的过程是这样的:

    1. 从磁盘读取文件内容到内核缓冲区
    2. 直接从内核缓冲区复制数据到socket缓冲区
    3. 从socket缓冲区复制到协议引擎(这里是网卡驱动)

    这种方式虽好,但是仍然存在一次从内核缓冲区到内核socket缓冲区的复制行为,也就是从内存的一个区域复制到内存的另一个区域的行为。这个是可以避免的吗?

    后来人们在硬件上进行了改进,在硬件的帮助下来消除内存数据之间的数据复制。这种硬件需要支持一种叫“收集”操作的接口,。它支持从内存中的不同位置收集数据,也就是不再限定于只从内核socket缓冲区来收集数据,而是可以从内核缓冲区去收集。

    2.4版本中对sendfile修改

    在linux内核版本2.4中对sendfile调用做了一系列优化来适应这个需求,避免了从内核缓冲区拷贝到socket buffer的操作,直接拷贝到协议栈,从而再一次减少了数据拷贝。具体如下图所示:
    在这里插入图片描述
    在上图中,数据复制到内核缓冲区以后,不再需要拷贝到socket缓冲区,而是需要将数据的位置和长度信息传输到socket缓冲区,这样DMA引擎会根据这些信息直接从内测缓冲区复制数据给协议引擎。

    最终,数据只需要从磁盘复制到内存,再从内存中复制到协议引擎,和最开始相比较少了2次复制,分别是:从内核复制到用户空间和从用户空间复制到socket缓冲。但是明明还有两次数据的复制,为什么要叫“零拷贝”呢?

    这是因为从操作系统的角度来说,数据没有从内存复制到内存的过程,也就没有了CPU参与的过程, 所以对于操作系统来说就是零拷贝了。查看wiki对零拷贝的定义如下:

    “Zero-copy” describes computer operations in which the CPU does not perform the task of copying data from one memory area to another.

    从定义我们看到,零拷贝是指不需要cpu参与在内存之间复制数据的操作。那这个过程为啥不需要cpu参与呢?

    仔细看上面的图示,你会发现:从磁盘复制到内核缓冲区是通过DMA引擎来做而不是cpu,同样的,从socket缓冲区到协议引擎也是由 DMA引擎来做,这样就节省了cpu的工作。而这整个过程都在内核中完成也减少了操作系统的上下文切换开销。

    再稍微讲讲 mmap 和 sendFile 的区别。

    1. mmap 适合小数据量读写,sendFile 适合大文件传输。
    2. mmap 需要 4 次上下文切换,3 次数据拷贝;sendFile 需要 3 次上下文切换,最少 2 次数据拷贝。
    3. sendFile 可以利用 DMA 方式,减少 CPU 拷贝,mmap 则不能(必须从内核拷贝到 Socket 缓冲区)。

    在这个选择上:rocketMQ 在消费消息时,使用了 mmap。kafka 使用了 sendFile。

    零拷贝的再次理解

    1. 存在用户空间和内核空间的交互行为就会产生上下文切换,所以即使用户空间与内核空间共享同一份缓冲区一样。
    2. 利用硬件支持的DMA引擎可以减少对CPU的使用,磁盘,网卡都有此引擎。
    3. 利用硬件的“收集”接口功能可以将数据位置和长度直接传输给硬件的相关引擎,从而让硬件引擎直接从相应的内存区域读取数据
    4. 零拷贝是用于对不变的数据做传输,如果应用程序需要修改数据那势必就不能用到零拷贝了,所以零拷贝不是万能的。

    哪些地方会用到零拷贝技术?

    1、java的NIO

    先说java,是因为要给下面的netty做铺垫,在 Java NIO 中的通道(Channel)就相当于操作系统的内核空间(kernel space)的缓冲区,而缓冲区(Buffer)对应的相当于操作系统的用户空间(user space)中的用户缓冲区(user buffer)。

    堆外内存(DirectBuffer)在使用后需要应用程序手动回收,而堆内存(HeapBuffer的数据在 GC 时可能会被自动回收。因此,在使用 HeapBuffer 读写数据时,为了避免缓冲区数据因为 GC 而丢失,NIO 会先把 HeapBuffer 内部的数据拷贝到一个临时的 DirectBuffer 中的本地内存(native memory),这个拷贝涉及到 sun.misc.Unsafe.copyMemory() 的调用,背后的实现原理与 memcpy() 类似。 最后,将临时生成的 DirectBuffer 内部的数据的内存地址传给 I/O 调用函数,这样就避免了再去访问 Java 对象处理 I/O 读写。
    (1)MappedByteBuffer
    MappedByteBuffer 是 NIO 基于内存映射(mmap)这种零拷贝方式的提供的一种实现,意思是把一个文件从 position 位置开始的 size 大小的区域映射为内存映像文件。这样之添加地址映射,而不进行拷贝。
    (2)DirectByteBuffer
    DirectByteBuffer 的对象引用位于 Java 内存模型的堆里面,JVM 可以对 DirectByteBuffer 的对象进行内存分配和回收管理,是 MappedByteBuffer 的具体实现类。因此同样具有零拷贝技术。
    (3)FileChannel
    FileChannel 定义了 transferFrom() 和 transferTo() 两个抽象方法,它通过在通道和通道之间建立连接实现数据传输的。
    我们直接看Linux2.4的版本,socket缓冲区做了调整,DMA带收集功能。
    (1)DMA从拷贝至内核缓冲区
    (2)将数据的位置和长度的信息的描述符增加至内核空间(socket缓冲区)
    (3)DMA将数据从内核拷贝至协议引擎
    这个复制过程是零拷贝过程。

    2、Netty

    Netty 中的零拷贝和上面提到的操作系统层面上的零拷贝不太一样, 我们所说的 Netty 零拷贝完全是基于(Java 层面)用户态的。
    (1)Netty 通过 DefaultFileRegion 类对FileChannel 的 tranferTo() 方法进行包装,相当于是间接的通过java进行零拷贝。
    (2)我们的数据传输一般都是通过TCP/IP协议实现的,在实际应用中,很有可能一条完整的消息被分割为多个数据包进行网络传输,而单个的数据包对你而言是没有意义的,只有当这些数据包组成一条完整的消息时你才能做出正确的处理,而Netty可以通过零拷贝的方式将这些数据包组合成一条完整的消息供你来使用。
    此时零拷贝的作用范围仅在用户空间中。那Netty是如何实现的呢?为此我们就要找到Netty进行数据传输的接口,这个接口一定包含了可以实现零拷贝的功能,这个接口就是ChannelBuffer。

    既然有接口肯定就有实现类,一个最主要的实现类是CompositeChannelBuffer,这个类的主要作用是将多个ChannelBuffer组成一个虚拟的ChannelBuffer来进行操作
    为什么说是虚拟的呢,因为CompositeChannelBuffer并没有将多个ChannelBuffer真正的组合起来,而只是保存了他们的引用,这样就避免了数据的拷贝,实现了Zero Copy。
    (3)ByteBuf 可以通过 wrap 操作把字节数组、ByteBuf、ByteBuffer 包装成一个 ByteBuf 对象, 进而避免了拷贝操作
    (4)ByteBuf 支持 slice 操作, 因此可以将 ByteBuf 分解为多个共享同一个存储区域的 ByteBuf,避免了内存的拷贝

    3、kafka
    Kafka 的索引文件使用的是 mmap + write 方式,数据文件使用的是 sendfile 方式。适用于系统日志消息这种高吞吐量的大块文件的数据持久化和传输。
    如果有10个消费者,传统方式下,数据复制次数为4*10=40次,而使用“零拷贝技术”只需要1+10=11次,一次为从磁盘复制到页面缓存,10次表示10个消费者各自读取一次页面缓存。

    参考:

    https://zhuanlan.zhihu.com/p/88789697

    https://blog.csdn.net/choumu8867/article/details/100658332

    https://blog.csdn.net/SDDDLLL/article/details/105565318

    https://www.cnblogs.com/ericli-ericli/articles/12923420.html

    有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~
    在这里插入图片描述

    展开全文
  • linux内核零拷贝技术

    千次阅读 2021-11-19 17:42:33
    零拷贝技术主要用于磁盘数据通过网络进行交互,常见用法卸载磁盘文件从网络发送出去。常规的卸载文件方法流程如下所示。 从上图可以看出软件流程一共复制了4次数据,内核态到用户态切换4次。 读操作(复制两次,上...
  • Linux平台下基于Intel千兆网卡的零拷贝技术的研究与实现.pdf
  • 零拷贝技术详细解读(Zero Copy)

    千次阅读 多人点赞 2020-10-09 16:49:19
    了解一下传统的文件传输如何实现零拷贝PageCache有什么用? 为什么要有DMA技术? 在没有 DMA 技术前,I/O 的过程是这样的: CPU 发出对应的指令给磁盘控制器,然后返回; 磁盘控制器收到指令后,于是就开始准备数据...
  • 零拷贝技术( DMA、PageCache)

    千次阅读 多人点赞 2021-01-28 14:48:09
    传统的文件传输有多糟糕零拷贝mmap + writesendfile真正的零拷贝PageCache大文件传输总结 为什么需要DMA? 在没有 DMA 技术前,I/O 的过程是这样的: CPU 发出对应的指令给磁盘控制器,然后返回; 磁盘控制器...
  • 当然,零拷贝技术不仅仅是RocketMQ一家独有的技术,也不仅仅只有MMAP一种零拷贝技术。比如说市面上另一种零拷贝方案:Sendfile。 Sendfile是通过直接操作磁盘上文件的方式进行零拷贝实现的,但是这种实现有一个弊端...
  • 零拷贝技术原理详解

    千次阅读 2020-04-23 19:20:50
    首先声明一个概念,通常说的零拷贝技术准确来说应该表达为:用户态零拷贝技术。 一、什么是零拷贝技术? 1.首先明确计算机数据传输过程 写一个小程序,完成一个从文件中读取数据,并传输到网络上的操作。 首先...
  • Kafka之零拷贝技术

    千次阅读 2021-06-15 08:04:17
    零拷贝技术(zero-copy)是指将数据直接才从磁盘文件复制到网卡设备中,不需要经过应用程序,减少了内核态和用户态的切换。jav
  • Linux小知识--零拷贝技术相关函数

    千次阅读 2021-11-22 11:36:04
    介绍了零拷贝技术的三个常用函数
  • 零拷贝是一个耳熟能详的词语,在linux,kafak,Rocket MQ等产品中都有使用,通常用户提升IO性能。传统Linux中的零拷贝:就是在数据操作时候,不需要从一个内存位置拷贝到另一个内存位置(比如从用户态拷贝到内核...
  • kafka零拷贝技术详解

    2021-03-16 17:55:00
    对 Linux 操作系统而言,零拷贝技术依赖于底层的 sendfile()方法实现。 对应于 Java 语言,FileChannal.transferTo() 方法的底层实现就是 sendfile() 方法。单纯从概念上理解“零拷贝”比较抽象,这里简单地介绍一下...
  • 什么是零拷贝技术,它们二者的零拷贝技术有不同吗? 为什么需要零拷贝 在计算机产业中,I/O的速度相较CPU,总是太慢的。SSD硬盘的IOPS可以达到2W、4W,但是我们CPU的主频有2GHz以上,也就意味着每秒会有20亿次的...
  • 零拷贝技术加速文件读写 Linux操作系统分为【用户态】和【内核态】,文件操作、网络操作需要涉及这两种形态的切换,免不 了进行数据复制。 一台服务器 把本机磁盘文件的内容发送到客户端,一般分为两个步骤: 1)read;...
  • 学习开发社区合作Linux 中的零拷贝技术,第 2 部分针对数据传输不需要经过应用程序地址空间的零拷贝技术在 Linux 中,减少拷贝次数的一种方法是调用 mm
  • 引言为什么需要零拷贝技术总结相关主题评论Linux 中的零拷贝技术,第 1 部分评论的时候,并没有类似 DMA 这种工具可以使用,CPU 需要全程参与到这种数据
  • 什么是零拷贝技术

    2020-08-02 10:47:22
    零拷贝技术,虽然平时接触到的比较少,但是确实大厂面试的热门,这里整理记录一下,虽不能完全领悟其原理,但至少要混个脸熟。 当应用程序访问数据时,操作系统首先会去检查,要访问的数据是否缓存在内核缓冲区,...
  • 点击上方“朱小厮的博客”,选择“设为星标”后台回复”加群“获取公众号专属群聊入口本文讲解 Linux 的零拷贝技术,云计算是一门很庞大的技术学科,融合了很多技术,Linux 算是比较基础...
  • 1. 首先,调用read时,文件A拷贝到了kernel模式 2. 之后,CPU控制将kernel模式数据copy到user模式下 3. 调用write时,先将u
  • 大白话讲解 零拷贝技术

    千次阅读 2022-03-28 11:09:55
    零拷贝的特点是CPU 不全程负责内存中的数据写入其他组件,CPU 仅仅起到管理的作用。但注意,零拷贝不是不进行拷贝,而是 CPU 不再全程负责数据拷贝时的搬运工作。如果数据本身不在内存中,那么必须先通过某种方式...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 53,921
精华内容 21,568
关键字:

零拷贝技术