什么是Zero-copy零拷贝

2023-05-16

考虑这样⼀种常⽤的情形:你需要将静态内容(类似图⽚、⽂件)展⽰给⽤户。那么这个情形就意味着你需要先将静态内容从磁盘中拷贝出来放到⼀个内存buf中,然后将这个buf通过socket传输给⽤户,进⽽⽤户或者静态内容的展⽰。这看起来再正常不过了,但是实际上这是很低效的流程,我们把上⾯的这种情形抽象成下⾯的过程:

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

⾸先调⽤read将静态内容,这⾥假设为⽂件A,读取到tmp_buf, 然后调⽤write将tmp_buf写⼊到socket中,如图:

 

在这个过程中⽂件A的经历了4次copy的过程:

  1. ⾸先,调⽤read时,⽂件A拷贝到了kernel模式;
  2. 之后,CPU控制将kernel模式数据copy到user模式下;
  3. 调⽤write时,先将user模式下的内容copy到kernel模式下的socket的buffer中;
  4. 最后将kernel模式下的socket buffer的数据copy到⽹卡设备中传送;

从上⾯的过程可以看出,数据⽩⽩从kernel模式到user模式⾛了⼀圈,浪费了2次copy(第⼀次,从kernel模式拷贝到user模式;第⼆次从user模式再拷贝回kernel模式,即上⾯4次过程的第2和3步骤。)。⽽且上⾯的过程中kernel和user模式的上下⽂的切换也是4次。

幸运的是,你可以⽤⼀种叫做Zero-Copy的技术来去掉这些⽆谓的copy。应⽤程序⽤Zero-Copy来请求kernel直接把disk的data传输给socket,⽽不是通过应⽤程序传输。

Zero-Copy⼤⼤提⾼了应⽤程序的性能,并且减少了kernel和user模式上下⽂的切换。Zero-Copy技术省去了将操作系统的read buffer拷贝到程序的buffer,以及从程序buffer拷贝到socket buffer的步骤,直接将read buffer拷贝到socket buffer.Java NIO中的FileChannal.transferTo()⽅法就是这样的实现,这个实现是依赖于操作系统底层的sendFile()实现的。

public void transferTo(long position, long count, WritableByteChannel target);

他底层的调⽤时系统调⽤sendFile()⽅法:

#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);

下图展⽰了在transferTo()之后的数据流向: 

 下图展⽰了在使⽤transferTo()之后的上下⽂切换:

 使⽤了Zero-Copy技术之后,整个过程如下:

  1. transferTo()⽅法使得⽂件A的内容直接拷贝到⼀个read buffer(kernel buffer)中;
  2. 然后数据(kernel buffer)拷贝到socket buffer中;
  3. 最后将socket buffer中的数据拷贝到⽹卡设备(protocol engine)中传输; 

这显然是⼀个伟⼤的进步:这⾥把上下⽂的切换次数从4次减少到2次,同时也把数据copy的次数从4次降低到了3次。但是这是Zero-Copy么,答案是否定的。

sendfile发展历程

Linux 2.1内核开始引⼊了sendfile函数(上⼀节有提到),⽤于将⽂件通过socket传送。

sendfile(socket, file, len);

该函数通过⼀次系统调⽤完成了⽂件的传送,减少了原来read/write⽅式的模式切换。此外更是减少了数据的copy, sendfile的详细过程如图: 

 通过sendfile传送⽂件只需要⼀次系统调⽤,当调⽤sendfile时:

  1. ⾸先(通过DMA)将数据从磁盘读取到kernel buffer中;
  2. 然后将kernel buffer拷贝到socket buffer中;
  3.  最后将socket buffer中的数据copy到⽹卡设备(protocol engine)中发送;

这个过程就是上一节(详述)中的那个步骤。

sendfiel与read/write模式相⽐,少了⼀次copy。但是从上述过程中也可以发现从kernel buffer中将数据copy到socket buffer是没有必要的。

Linux2.4 内核对sendfile做了改进,如图:

 改进后的处理过程如下:

  1.  将⽂件拷贝到kernel buffer中;
  2. 向socket buffer中追加当前要发⽣的数据在kernel buffer中的位置和偏移量;
  3. 根据socket buffer中的位置和偏移量直接将kernel buffer的数据copy到⽹卡设备(protocol engine)中;

经过上述过程,数据只经过了2次copy就从磁盘传送出去了。 

这个才是真正的Zero-Copy(这⾥的零拷贝是针对kernel来讲的,数据在kernel模式下是Zero-Copy)。

正是Linux2.4的内核做了改进,Java中的TransferTo()实现了Zero-Copy,如下图: 

 Zero-Copy技术的使⽤场景有很多,⽐如Kafka, 又或者是Netty等,可以⼤⼤提升程序的性能。

本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系:hwhale#tublm.com(使用前将#替换为@)

什么是Zero-copy零拷贝 的相关文章

随机推荐

  • Airsim通过ros发布激光雷达数据+Lego-loam仿真测试(2)

    上篇博客只是简单跑通了流程 xff0c 存在的问题将在这篇进行修正 一 Lego loam里话题订阅 雷达点云话题为 xff1a velodyne points xff0c frame id为velodyne IMU话题为 xff1a Im
  • [控制算法]

    常用控制算法 0 博览众长 0 1 视频 1 DR CAN b站 0 2 文章 1 控制算法整理 0 3 传统 VS 现代控制算法 1 传统 传统控制算法 xff1a PID xff0c 模糊 xff0c 神经网络控制算法 2 现代 现代控
  • 七、输入/输出流--streambuffer类介绍--

    缓冲区类 类模板定义为basic streambuf xff0c 由 lt iostream gt 给出 xff1a 1 stream缓冲区 通常stream不负责实际读写操作 xff0c 而是stream buffer实现streambu
  • 七、输入/输出流--streambuffer类介绍--自定义缓冲区

    基本上没看懂 xff0c 那个大神如果可以的话 xff0c 推荐一点相关资料 xff0c 真的不太明白这个缓冲区的内部原理 3 自定义缓冲区 缓冲区有basic streambuf定义 xff0c 针对字型为char和wchar标准库提供了
  • 串口通信学习(GPS模块)2021.5.10

    GPS串口通信学习实践 2021 5 10 1 串口通信简介1 1 波特率1 2 数据位1 3 停止位1 4 奇偶校验位 2 GPS模块串口通信配置2 1 驱动安装2 2 插入GPS模块2 3 GPS模块串口通信数据简介 3 Java实现G
  • Lambda表达式的使用

    对于jdk1 8其实并不是那么熟悉 xff0c 但是要学习这一点 xff0c 对以后工作有好处 xff0c 接下来开始学习jdk1 8在Android studio的配置以及lambda表达式的使用吧 Lambda表达式 jdk1 8中新增
  • ROS实现无人机目标跟踪/物体跟随/循迹

    无人机自主物体跟随 循迹 1 物体跟踪1 1 实现思路1 2 代码示例 2 自主寻线 本实验采用ROS和OpenCV实现功能 xff0c 实验平台采用Parrot的Bebop2无人机ROS部分的学习可以参考我的专栏 xff1a ROS学习记
  • vs code中项目的基本配置--include路径、运行参数、debug配置

    1 安装C C 43 43 for Visual Studio Code 点击左边扩展栏图标 gt 搜索C C 43 43 gt 安装 gt Reload xff1a 安装完成之后 xff0c 打开你的包含c 43 43 的文件夹 xff0
  • CMakeLists.txt编写规范模板及CMake常用变量

    文章目录 基本语法规则常见CMakeLists txt中指令剖析从VS项目配置过程理解CMakeLists内容CMake中常用变量汇总常用CMakeLists文件模板 基础模板使用OpenCV库CMakeLists文件模板使用PCL库CMa
  • C++ 多线程detach()操作的坑以及传参

    detach 的作用是将子线程和主线程的关联分离 xff0c 也就是说detach 后子线程在后台独立继续运行 xff0c 主线程无法再取得子线程的控制权 xff0c 即使主线程结束 xff0c 子线程未执行也不会结束 当主线程结束时 xf
  • 条件变量中的唤醒丢失问题分析

    本文是在其他作者博文的基础上进行了部分补充 原文 xff1a https zhuanlan zhihu com p 55123862 0 前言 条件变量 xff08 condition variable xff09 和互斥锁 xff08 m
  • 无人车传感器 IMU与GPS数据融合进行定位机制

    前言 上一次的分享里 xff0c 我介绍了GPS的原理 xff08 三角定位 xff09 及特性 xff08 精度 频率 xff09 xff0c 同时也从无人车控制的角度 xff0c 讨论了为什么仅有GPS无法满足无人车的定位要求 为了能让
  • C++类对象的赋值与=运算符重载

    本文主要介绍C 43 43 中的赋值运算符重载函数 xff08 operator 61 xff09 的相关知识 1 概述 1 1 why 首先介绍为什么要对赋值运算符 61 进行重载 某些情况下 xff0c 当我们编写一个类的时候 xff0
  • 微信小程序开发入门(一)

    所有示例的完整代码 xff0c 都可以从 GitHub 的代码仓库下载 一 小程序是什么 xff1f 学习小程序之前 xff0c 先简单说一下 xff0c 它到底是什么 字面上讲 xff0c 小程序就是微信里面的应用程序 xff0c 外部代
  • rtp载荷H264解包过程分析,ffmpeg解码qt展示

    网络抽象层单元 NALU NALU头 NALU 头 由1个byte组成 它的语法如下 43 43 0 1 2 3 4 5 6 7 43 43 43 43 43 43 43 43 43 F NRI Type 43 43 F 1 个比特 for
  • CPU上下文切换、进程上下文、中断上下文

    由于Linux是一个多任务操作系统 xff0c 能够支持远大于CPU数量的任务同时运行 当然 xff0c 这些任务实际上并不是真的在同时运行 xff0c 而是由CPU进行调度 xff0c 将时间分片 xff0c 每个任务占用1个时间片 xf
  • Gstreamer概述

    1 什么是GStreamer GStreamer 是用来构建流媒体应用的开源多媒体框架 framework xff0c 其基本设计思想来自于俄勒冈 Oregon 研究生学院有关视频管道的创意 同时也借鉴了DirectShow的设计思想 其目
  • grbl学习之旅---serial篇

    serial c和serial h文件是实现了通过串行端口发送和接受字节的功能 首先是serial h中定义了基本函数和常量大小 xff1a ifndef RX BUFFER SIZE define RX BUFFER SIZE 128 定
  • ip rule,ip route,iptables 三者之间的关系

    以一例子来说明 xff1a 公司内网要求192 168 0 100 以内的使用 10 0 0 1 网关上网 xff08 电信 xff09 xff0c 其他IP使用 20 0 0 1 xff08 网通 xff09 上网 首先要在网关服务器上添
  • 什么是Zero-copy零拷贝

    考虑这样 种常 的情形 xff1a 你需要将静态内容 xff08 类似图 件 xff09 展 给 户 那么这个情形就意味着你需要先将静态内容从磁盘中拷贝出来放到 个内存buf中 xff0c 然后将这个buf通过socket传输给 户 xff