今天搞懂Linux零拷贝(linux操作系统拷贝命令)
ahcoder 2025-03-18 09:42 11 浏览
Linux零拷贝
很多人都听过零拷贝zero-copy的大名,知道在很多牛掰的中间件(比如rocketmq)中为了提高效率,都是用了这项技术。
但是,zero-copy到底是怎么回事?
今天我想把他彻底搞明白。
什么是zero-copy
为了搞明白一个技术方案,首先我们应该搞明白这个技术是为了解决什么问题。先理解问题,才能理解答案。
我们先看一个简单的场景,服务器需要将磁盘文件中的数据通过网络发送给客户端。在这个场景下都发生了什么?
你可能觉得这只是两个系统间的调用,数据从一个服务器copy到另一台服务器。但事实上,在操作系统层面发生的事情要复杂得多。
在传统模式下,至少会copy四次数据,下面会细讲。所以,为了减少copy次数,提高效率,诞生了zero-copy方案。
zero-copy并不是真的一次都不copy,而是站在内核空间的角度讲,没有进行内核空间和用户空间之间的copy。
看不懂这几个名词没关系,下面会细讲。
前置知识
Linux系统的“用户空间”和“内核空间”
首先要知道,Linux操作系统分为【用户态user context】和【内核态 kernel context】,
从Linux系统上看,除了引导系统的BIN区,整个内存空间主要被分成两个部分:内核空间(Kernel space)、用户空间(User space)。“用户空间”和“内核空间”的空间、操作权限以及作用都是不一样的。文件操作、网络操作需要涉及这两种上下文的切换,免不了进行数据复制。
内核空间是Linux自身使用的内存空间,主要提供给程序调度、内存分配、连接硬件资源等程序逻辑使用;
用户空间则是提供给各个进程的主要空间。用户空间不具有访问内核空间资源的权限,因此如果应用程序需要使用到内核空间的资源,则需要通过系统调用来完成:从用户空间切换到内核空间,然后在完成相关操作后再从内核空间切换回用户空间
DMA
DMA(Direct Memory Access) ———— 直接内存访问 :DMA是允许外设组件将I/O数据直接传送到主存储器中并且传输不需要CPU的参与,以此将CPU解放出来去完成其他的事情。 而用户空间与内核空间之间的数据传输并没有类似DMA这种可以不需要CPU参与的传输工具,因此用户空间与内核空间之间的数据传输是需要CPU全程参与的。所有也就有了通过零拷贝技术来减少和避免不必要的CPU数据拷贝过程。
传统做法
在普通的做法中,这个简单的数据复制过程,至少经过了4次的数据复制。
下面这张图,上半部分是上下文的切换,下半部分是数据复制操作
已java为例讲解
第一步:首先jvm向操作系统发出read()系统调用,此时会要将上下文从用户态切换到内核态。将数据从磁盘copy到内核地址空间buffer中,这一步copy是由DMA(直接内存访问)引擎执行的,这是第一次copy
第二步:linux的read操作结束退出,此时会将上下文切换回用户态,同时将数据从内核缓冲区拷贝到用户空间缓冲区。这里用的是CPU。这是第二次copy
之后需要将数据写给网卡进行发送
第三步:jvm向OS发起write()系统调用。系统上下文由用户态切换为内核态。系统的write操作将数据从用户空间buffer复制到内核空间的socket buffer。现在数据又回到了内核buffer,当然这和第一步的内核buffer不是一个空间。这是第三次copy。用的是cpu。
第四步:write操作返回,系统切换回用户态。同时,系统通过DMA将socket buffer中的数据copy到底层硬件(网卡)缓冲区。(这是一个独立且异步的操作,和write操作无关)
下面这个图更清晰些
可以看到,数据在内核空间和用户空间之间,被来来回回的复制。同时伴随着系统上下文的切换。我们知道,上下文切换是CPU密集型的工作,数据拷贝是I/O密集型的工作。如果一次简单的传输就要像上面这样复杂的话,效率是相当低下的。零拷贝机制的终极目标,就是消除冗余的上下文切换和数据拷贝,提高效率。
sendfile
为了做到这点,linux内核从2.1版本开始,提供了名为sendfile()的系统调用。不仅能减少数据copy,而且能减少系统上下文切换。
看图,从图的上半部分看出,sendfile方式,只有2次上下文的切换。
在数据copy方面。
第一步,从硬盘copy进内核空间,DMA。
第二步,内核buffer到socket buffer的copy。用的cpu。注意这里的copy只在内核空间,不涉及用户空间。
第三步,从socket buffer 到网卡,DMA
ok,目前我们省了1次上下文切换,省了内核空间和用户空间的cpu copy
但是,我们看到在内核空间中,还有一次cpu copy。直觉告诉我们,这次copy还是没有什么用。
为什么会有这一步呢?
这是因为在一般的Block DMA方式中,源物理地址和目标物理地址都得是连续的,所以一次只能传输物理上连续的一块数据,每传输一个块发起一次中断,直到传输完成,所以必须要在两个缓冲区之间拷贝数据。
那么能否省去这一步呢?
对Scatter/Gather的支持的IO
Scatter/Gather技术的意思是分散然后收集。
从kernel 2.4版本开始,socket buffer的描述符做了优化。描述符中包含有数据的起始地址和长度。传输时只需要遍历链表,按序传输数据,全部完成后发起一次中断即可,效率比Block DMA要高。也就是说,硬件可以通过Scatter/Gather DMA直接从内核缓冲区中取得全部数据,不需要再从内核缓冲区向Socket缓冲区拷贝数据。
这样,又省区了cpu拷贝。
到现在为止,从用户空间角度看,是0次copy。从CPU的角度看,也是0次copy。
所以zero-copy完成。
那么,现在是不是完美了呢?其实是有一个问题的。
现在数据一直在内核空间,用户空间没有数据,那么我们的程序就不能对数据进行任何修改操作。如果我们有修改的需求,sendfile实现是不行的。
进而,引出了下面这个。
mmap
mmap是内存映射。他要比sendfile效率差,但是比传统方式又高效的一种方案。
mmap的特点是,不会将数据从内核空间copy到用户空间。而是在用户空间共享内核空间的数据。从而可以对数据进行修改。
从效率上来说,mmap也是有4次上下文切换,和三次的数据copy。相比传统方式是省了一次cpu copy。
java的NIO
java的NIO中,常用的FileChannel。有个map方法,FileChannel的map方法会返回一个MappedByteBuffer。MappedByteBuffer是一个直接字节缓冲器,该缓冲器的内存是一个文件的内存映射区域。map方法底层是通过mmap实现的,因此将文件内存从磁盘读取到内核缓冲区后,用户空间和内核空间共享该缓冲区。
相关推荐
- ARM64内核内存布局图(ARM64内核内存布局图解)
-
ARM64架构处理器采用48位物理寻址机制,最大可以寻找到256TB的物理地址空间。对于目前的应用来说已经足够了,不需要扩展到64位的物理地址寻址。虚拟地址也同样最大支持48位支持,所以在处理器的架构...
- ARM64 linux 调试串口通信(ARM64 linux 调试串口通信实验报告)
-
ARM64linux调试串口通信随着国产机普及很多工作也转移到了新平台上,以前调试设备用的笔记本电脑也换成新国产ARM64架构的了。本文以绿联CM204USB-A转RJ45Console调试线...
- Gentoo Linux 终止对 Itanium IA-64 体系的支持
-
GentooLinux是最后几个继续维护Itanium(IA-64)架构构建的Linux发行版之一,但现在这些已停产的英特尔处理器正在逐步淘汰。由于Linux6.7内核放弃了对Itan...
- 如何检查 Linux 系统是 32 位还是 64 位?这9个命令查的又快又准!
-
在Linux系统中,位数(bit)通常指的是CPU架构的位宽,即CPU一次能够处理的数据量。32位系统和64位系统在内存寻址能力、计算性能和软件支持上存在显著差异:「32位系统」:...
- 调出好画面!带你玩转飞凌嵌入式AM62x开发板的显示接口
-
来源:飞凌嵌入式官网“显示”是嵌入式开发板最为重要的功能之一,能够支持更多种类、更高规格的显示接口,意味着它能够应对的使用场景也更加广泛。每一款嵌入式开发板在出厂前都会做屏幕调试,但在客户的实际项目开...
- 带你玩转AM62x开发板的显示接口——LVDS的显示和修改方式
-
此前小编已为大家介绍过OK6254-C开发板的RGB显示和修改方式,今天将继续为大家介绍OK6254-C开发板的LVDS显示和修改方式。话不多说,我们进入正题。1、LVDS接口规格飞凌嵌入式OK62...
- AM335x继任者?AM6254性能解析(am2361p)
-
飞凌嵌入式FET6254-C核心板基于TISitaraTMAM62x系列工业级处理器设计开发,采用ARMCortex-A53架构,主频最高可达1.4GHz;并集成了丰富的接口,可广泛应用于的工...
- 如何在 Linux 发行版中安装微信和 QQ?
-
很多人因为工作沟通的原因需要用到微信和QQ,那么如何在Linux发行版中安装微信和QQ呢?以下是一些尝试的解决方法。QQ上一个版本的QQLinux版还是在2009年,而在现在,基于N...
- MySQL:物理备份工具XBK(mysql 备份方案)
-
XBK的优缺点:XBK(PerconaXtraBackup)优点:1.免费2.热备:备份期间不阻塞innodb和XtraDB表,但会阻塞Myisam表3.物理备份:备份恢复快XBK缺点:1.不支持远...
- AMD锐龙9 9950X CPU AIDA64跑分曝光:比7950X最高快45%
-
IT之家6月26日消息,Anandtech论坛网友igor_kavinski本周一发布帖子,分享了AMD旗舰锐龙99950X处理器的AIDA64基准测试跑分,与当前基于Z...
- qemu linux内核(5.10.209)开发环境搭建
-
版本信息宿主机:ubuntu20.04.6LTS(FocalFossa)虚拟机:ubuntu20.04.6LTS(FocalFossa)安装宿主机的步骤省略,和一般的在vmware中安...
- iPhone 7成刷机神器,成功运行乌班图、Linux、安卓
-
在智能机刚开始流行的时候,很多手机发烧友都喜欢刷机,当时民间大神们制作了特别多优化的ROM。后来随着手机硬件的逐步提升,以及厂商们对系统的大力优化,让大家对于刷机的兴趣也越来越少。不知道大家还记得这部...
- 12 款最佳免费开源 Linux 渲染器 | 火狐浏览器 130.0 版本更新
-
12款最佳免费开源Linux渲染器Linux的一大优势在于其拥有丰富的开源软件,可以满足艺术家、摄影师、动画师和设计师的需求。凭借价格低廉的硬件、免费的软件以及少量的才能和灵感,任何人都可以创...
- Linux中xargs 命令详解与实用场景
-
xargs是Linux系统中常用的命令行工具之一,它能够从标准输入构造参数列表并传递给其他命令使用,是处理批量数据操作时的重要利器。一、xargs的基本语法xargs[OPTION]...[C...
- Linux 磁盘扩容(非LVM)方式(linux扩容lvm磁盘容量)
-
今天接到一个客户的需求,CentOS的/分区容量太小了,OA系统所有的数据都在这下面,由于当时前同事给客户安装系统时采用了标准分区,而不是LVM逻辑卷,所以不支持在线扩容。df-hT查看磁盘使...
- 一周热门
- 最近发表
-
- ARM64内核内存布局图(ARM64内核内存布局图解)
- ARM64 linux 调试串口通信(ARM64 linux 调试串口通信实验报告)
- Gentoo Linux 终止对 Itanium IA-64 体系的支持
- 如何检查 Linux 系统是 32 位还是 64 位?这9个命令查的又快又准!
- 调出好画面!带你玩转飞凌嵌入式AM62x开发板的显示接口
- 带你玩转AM62x开发板的显示接口——LVDS的显示和修改方式
- AM335x继任者?AM6254性能解析(am2361p)
- 如何在 Linux 发行版中安装微信和 QQ?
- MySQL:物理备份工具XBK(mysql 备份方案)
- AMD锐龙9 9950X CPU AIDA64跑分曝光:比7950X最高快45%
- 标签列表
-
- linux 远程 (37)
- u盘 linux (32)
- linux 登录 (34)
- linux 路径 (33)
- linux 文件命令 (35)
- linux 是什么 (35)
- linux 界面 (34)
- 查看文件 linux (35)
- linux 语言 (33)
- linux代码 (32)
- linux 查看命令 (33)
- 关闭linux (34)
- root linux (33)
- 删除文件 linux (35)
- linux 主机 (34)
- linux与 (33)
- linux 函数 (35)
- linux .ssh (35)
- cpu linux (35)
- 查看linux 系统 (32)
- linux 防火墙 (33)
- linux 手机 (32)
- linux 镜像 (34)
- linux mac (32)
- linux ip地址 (34)