图解I/O中的零拷贝技术
什么是零拷贝?
零拷贝是一种计算机系统中的 I/O 优化技术,它的核心思想是在数据传输过程中尽可能地减少或完全避免 CPU 将数据从一个存储区域复制到另一个存储区域的操作,从而减少了上下文切换和 CPU 拷贝时间,提高了系统的性能和效率。在 Java 领域,诸如 Netty、Kafka、RocketMQ 等框架就使用了零拷贝技术来提高性能和效率,尤其在处理大规模数据传输时表现突出。
什么是 DMA 技术?
直接内存访问(Direct Memory Access) 技术。简单理解就是,在进行 I/O 设备和内存的数据传输的时候,数据搬运的工作全部交给 DMA 控制器,而 CPU 不再参与任何与数据搬运相关的事情,这样 CPU 就可以去处理别的事务。
传统I/O是如何操作的?
read(file, tmp_buf, len);
write(socket, tmp_buf, len);
期间共发生了 4 次用户态与内核态的上下文切换,因为发生了两次系统调用,一次是 read()
,一次是 write()
,每次系统调用都得先从用户态切换到内核态,等内核完成任务后,再从内核态切换回用户态。
其次,还发生了 4 次数据拷贝,其中两次是 DMA 的拷贝,另外两次则是通过 CPU 拷贝的:
- 第一次拷贝,把磁盘上的数据拷贝到操作系统内核的缓冲区里,这个拷贝的过程是通过 DMA 搬运的。
- 第二次拷贝,把内核缓冲区的数据拷贝到用户的缓冲区里,于是我们应用程序就可以使用这部分数据了,这个拷贝到过程是由 CPU 完成的。
- 第三次拷贝,把刚才拷贝到用户的缓冲区里的数据,再拷贝到内核的 socket 的缓冲区里,这个过程依然还是由 CPU 搬运的。
- 第四次拷贝,把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程又是由 DMA 搬运的。
那零拷贝的方案有哪些呢?
1、Mmap+Write
在前面我们知道,read()
系统调用的过程中会把内核缓冲区的数据拷贝到用户的缓冲区里,于是为了减少这一步开销,我们可以用 mmap()
替换 read()
系统调用函数。
buf = mmap(file, len);
write(sockfd, buf, len);
mmap()
系统调用函数会直接把内核缓冲区里的数据「映射」到用户空间,这样,操作系统内核与用户空间就不需要再进行任何的数据拷贝操作。
具体过程如下:
- 应用进程调用了
mmap()
后,DMA 会把磁盘的数据拷贝到内核的缓冲区里。接着,应用进程跟操作系统内核「共享」这个缓冲区; - 应用进程再调用
write()
,操作系统直接将内核缓冲区的数据拷贝到 socket 缓冲区中,这一切都发生在内核态,由 CPU 来搬运数据; - 最后,把内核的 socket 缓冲区里的数据,拷贝到网卡的缓冲区里,这个过程是由 DMA 搬运的。
我们可以得知,通过使用 mmap()
来代替 read()
, 可以减少一次数据拷贝的过程。
但这还不是最理想的零拷贝,因为仍然需要通过 CPU 把内核缓冲区的数据拷贝到 socket 缓冲区里,而且仍然需要 4 次上下文切换,因为系统调用还是 2 次。
2、SendFile
在 Linux 内核版本 2.1 中,提供了一个专门发送文件的系统调用函数 sendfile()
,函数形式如下:
#include <sys/socket.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
它的前两个参数分别是目的端和源端的文件描述符,后面两个参数是源端的偏移量和复制数据的长度,返回值是实际复制数据的长度。
首先,它可以替代前面的 read()
和 write()
这两个系统调用,这样就可以减少一次系统调用,也就减少了 2 次上下文切换的开销。
其次,该系统调用,可以直接把内核缓冲区里的数据拷贝到 socket 缓冲区里,不再拷贝到用户态,这样就只有 2 次上下文切换,和 3 次数据拷贝。如下图:
但是这还不是真正的零拷贝技术,如果网卡支持 SG-DMA(The Scatter-Gather Direct Memory Access)技术(和普通的 DMA 有所不同),我们可以进一步减少通过 CPU 把内核缓冲区里的数据拷贝到 socket 缓冲区的过程。
具体过程如下:
- 第一步,通过 DMA 将磁盘上的数据拷贝到内核缓冲区里;
- 第二步,缓冲区描述符和数据长度传到 socket 缓冲区,这样网卡的 SG-DMA 控制器就可以直接将内核缓存中的数据拷贝到网卡的缓冲区里,此过程不需要将数据从操作系统内核缓冲区拷贝到 socket 缓冲区中,这样就减少了一次数据拷贝;
这就是所谓的零拷贝(Zero-copy)技术,因为我们没有在内存层面去拷贝数据,也就是说全程没有通过 CPU 来搬运数据,所有的数据都是通过 DMA 来进行传输的。
总结:
I/O操作 | 数据拷贝次数 | 上下文切换次数 |
传统I/O | 2次CPU拷贝,2次DMA拷贝 | 4 |
Mmap+Write | 1次CPU拷贝,2次DMA拷贝 | 4 |
SendFile | 1次CPU拷贝,2次DMA拷贝 | 2 |
SendFile + 支持 SG-DMA | 1次DMA拷贝,1次SG-DMA拷贝 | 2 |
零拷贝技术的文件传输方式相比传统文件传输的方式,减少了 2 次上下文切换和数据拷贝次数,只需要 2 次上下文切换和数据拷贝次数,就可以完成文件的传输,而且 2 次的数据拷贝过程,都不需要通过 CPU,2 次都是由 DMA 来搬运。
所以,总体来看,零拷贝技术可以把文件传输的性能提高至少一倍以上。
ps:以下是我整理的java面试资料,感兴趣的可以看看。最后,创作不易,觉得写得不错的可以点点关注!
链接:https://www.yuque.com/u39298356/uu4hxh?# 《Java面试宝典》
相关文章:

图解I/O中的零拷贝技术
什么是零拷贝? 零拷贝是一种计算机系统中的 I/O 优化技术,它的核心思想是在数据传输过程中尽可能地减少或完全避免 CPU 将数据从一个存储区域复制到另一个存储区域的操作,从而减少了上下文切换和 CPU 拷贝时间,提高了系统的性能和…...
【设计模式】Java 设计模式之桥接模式(Bridge)
桥接模式(Bridge Pattern)是结构型设计模式的一种,它主要解决的是抽象部分与实现部分的解耦问题,使得两者可以独立变化。这种类型的设计模式属于结构型模式,因为该模式涉及如何组合接口和它们的实现。将抽象部分与实现…...

记录dockers中Ubuntu安装python3.11
参考: docker-ubuntu 安装python3.8,pip3_dockerfile ubuntu22 python3.8-CSDN博客...

【算法专题--双指针算法】leetcode--283. 移动零、leetcode--1089. 复写零
🍁你好,我是 RO-BERRY 📗 致力于C、C、数据结构、TCP/IP、数据库等等一系列知识 🎄感谢你的陪伴与支持 ,故事既有了开头,就要画上一个完美的句号,让我们一起加油 目录 前言1. 移动零࿰…...

【JavaEE -- 多线程3 - 多线程案例】
多线程案例 1.单例模式1.1 饿汉模式的实现方法1.2 懒汉模式的实现方法 2. 阻塞队列2.1 引入生产消费者模型的意义:2.2 阻塞队列put方法和take方法2.3 实现阻塞队列--重点 3.定时器3.1 定时器的使用3.2 实现定时器 4 线程池4.1 线程池的使用4.2 实现一个简单的线程池…...
k8s的pod服务升级,通过部署helm升级
要通过Helm升级Kubernetes(k8s)中的Pod服务,你可以按照以下步骤进行操作: 安装Helm: 如果你还没有安装Helm,可以通过官方文档提供的方式进行安装。添加Helm仓库: 确保你已经添加了包含你要升级…...

复现文件上传漏洞
一、搭建upload-labs环境 将下载好的upload-labs的压缩包,将此压缩包解压到WWW中,并将名称修改为upload,同时也要在upload文件中建立一个upload的文件。 然后在浏览器网址栏输入:127.0.0.1/upload进入靶场。 第一关 选择上传文件…...
Java 内存异常
内存溢出 内存溢出指的是在程序执行过程中,申请的内存超过了系统实际可用的内存资源。 内存溢出的常见情况: 创建大量对象并持有引用:在程序中创建大量对象并持有对这些对象的引用,而没有及时释放这些引用,导致堆内存…...

Windows11去掉 右键菜单的 AMD Software:Adrenalin Edition 选项
Windows11去掉 右键菜单的 AMD Software:Adrenalin Edition 选项 运行regedit打开注册表编辑器 先定位到 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PackagedCom\Package 计算机\HKEY_LOCAL_MACHINE\SOFTWARE\Classes\PackagedCom\Package找到 AdvancedMicroDevicesInc-2.…...
uniapp实现我的订单页面无感 - 删除数据
在进入我们的订单页面时进行获取列表,上拉加载,下拉刷新等请求,我们在删除数据时,请求删除接口后,不要重新去请求数据,不要重新去请求数据,不要重新去请求数据 重新请求会刷新页面中的数据 方…...

MySQL—redo log、undo log以及MVCC
MySQL—redo log、undo log以及MVCC 首先回忆一下MySQL事务的四大特性:ACID,即原子性、一致性、隔离性和持久性。其中原子性、一致性、持久性实际上是由InnoDB中的两份日志保证的,一份是redo log日志,一份是undo log日志ÿ…...
13 list的实现
注意 实现仿cplus官网的list类,对部分主要功能实现 实现 文件 #pragma once #include <assert.h>namespace mylist {template <typename T>struct __list_node{__list_node(const T& x T()): _prev(nullptr), _next(nullptr), _data(x){}__lis…...
如何用client-go获取k8s因硬盘容量、cpu、内存、gpu资源不够引起的错误信息?
在Kubernetes中,你可以使用client-go库来获取Pod的状态和事件,这些信息可能包含了由于资源不足引起的错误信息。 以下是一个基本的示例,展示如何使用client-go来获取Pod的状态和事件: package mainimport ("flag"&quo…...

IDEA编译安卓源码TVBox(2)
一、项目结构:主要app和player app结构 二、增加遥控器按键选台 修改LivePlayActivity.java 1、声明变量 public String channelId "";public Timer timer new Timer();public Toast mToast;2、定义方法 private void mToastShow(String s){mToast …...

【C#】.net core 6.0 使用第三方日志插件Log4net,配置文件详细说明
欢迎来到《小5讲堂》 大家好,我是全栈小5。 这是《C#》系列文章,每篇文章将以博主理解的角度展开讲解, 特别是针对知识点的概念进行叙说,大部分文章将会对这些概念进行实际例子验证,以此达到加深对知识点的理解和掌握。…...

第十四届蓝桥杯省赛真题 Java 研究生 组【原卷】
文章目录 发现宝藏【考生须知】试题 A: 特殊日期试题 B: 与或异或试题 C: 棋盘试题 D: 子矩阵试题 E : \mathrm{E}: E: 互质数的个数试题 F: 小蓝的旅行计划试题 G: 奇怪的数试题 H: 太阳试题 I: 高塔试题 J \mathrm{J} J : 反异或 01 串 发现宝藏 前些天发现了一个巨牛的人…...
adb shell input text 输入中文
由于adb 不支持中文输入(不支持 Unicode),需要使用虚拟键盘绕一圈。 可以直接参考和使用: https://github.com/senzhk/ADBKeyBoard # 通用方式 adb shell am broadcast -a ADB_INPUT_TEXT --es msg 赞 # mac/linux 支持 base64…...

Rudolf and the Ball Game
传送门 题意 思路 暴力枚举每一个妆台的转换条件 code #include<iostream> #include<cstdio> #include<stack> #include<vector> #include<algorithm> #include<cmath> #include<queue> #include<cstring> #include<ma…...

计算机毕业设计-基于大数据技术下的高校舆情监测与分析
收藏和点赞,您的关注是我创作的动力 文章目录 概要 一、研究背景与意义1.1背景与意义1.2 研究内容 二、舆情监测与分析的关键技术2.1 robot协议对本设计的影响2.2 爬虫2.2.1 工作原理2.2.2 工作流程2.2.3 抓取策略2.3 scrapy架构2.3.1 scrapy:开源爬虫架…...
WPF使用LiveCharts画图时,横坐标转换成时间
一、背景 使用LiveCharts画图时,横坐标通常为数值类型,要转换成时间等自定义类型,需要用到Formatter进行类型转换。 示例使用MVVM模式编写 二、View代码 关键是设置LabelFormatter属性 <lvc:CartesianChart Series"{Binding Series…...
Java 语言特性(面试系列1)
一、面向对象编程 1. 封装(Encapsulation) 定义:将数据(属性)和操作数据的方法绑定在一起,通过访问控制符(private、protected、public)隐藏内部实现细节。示例: public …...

K8S认证|CKS题库+答案| 11. AppArmor
目录 11. AppArmor 免费获取并激活 CKA_v1.31_模拟系统 题目 开始操作: 1)、切换集群 2)、切换节点 3)、切换到 apparmor 的目录 4)、执行 apparmor 策略模块 5)、修改 pod 文件 6)、…...
k8s从入门到放弃之Ingress七层负载
k8s从入门到放弃之Ingress七层负载 在Kubernetes(简称K8s)中,Ingress是一个API对象,它允许你定义如何从集群外部访问集群内部的服务。Ingress可以提供负载均衡、SSL终结和基于名称的虚拟主机等功能。通过Ingress,你可…...
FFmpeg 低延迟同屏方案
引言 在实时互动需求激增的当下,无论是在线教育中的师生同屏演示、远程办公的屏幕共享协作,还是游戏直播的画面实时传输,低延迟同屏已成为保障用户体验的核心指标。FFmpeg 作为一款功能强大的多媒体框架,凭借其灵活的编解码、数据…...
【Java学习笔记】Arrays类
Arrays 类 1. 导入包:import java.util.Arrays 2. 常用方法一览表 方法描述Arrays.toString()返回数组的字符串形式Arrays.sort()排序(自然排序和定制排序)Arrays.binarySearch()通过二分搜索法进行查找(前提:数组是…...

python/java环境配置
环境变量放一起 python: 1.首先下载Python Python下载地址:Download Python | Python.org downloads ---windows -- 64 2.安装Python 下面两个,然后自定义,全选 可以把前4个选上 3.环境配置 1)搜高级系统设置 2…...
Objective-C常用命名规范总结
【OC】常用命名规范总结 文章目录 【OC】常用命名规范总结1.类名(Class Name)2.协议名(Protocol Name)3.方法名(Method Name)4.属性名(Property Name)5.局部变量/实例变量(Local / Instance Variables&…...

微信小程序 - 手机震动
一、界面 <button type"primary" bindtap"shortVibrate">短震动</button> <button type"primary" bindtap"longVibrate">长震动</button> 二、js逻辑代码 注:文档 https://developers.weixin.qq…...
【Go】3、Go语言进阶与依赖管理
前言 本系列文章参考自稀土掘金上的 【字节内部课】公开课,做自我学习总结整理。 Go语言并发编程 Go语言原生支持并发编程,它的核心机制是 Goroutine 协程、Channel 通道,并基于CSP(Communicating Sequential Processes࿰…...

零基础设计模式——行为型模式 - 责任链模式
第四部分:行为型模式 - 责任链模式 (Chain of Responsibility Pattern) 欢迎来到行为型模式的学习!行为型模式关注对象之间的职责分配、算法封装和对象间的交互。我们将学习的第一个行为型模式是责任链模式。 核心思想:使多个对象都有机会处…...