搞懂零拷贝这一篇文章就够了
目录
一、缓冲I/O和直接I/O
1、应用程序内存
2、用户缓冲区
3、内核缓冲区
二、内存映射文件与零拷贝
1、内存映射文件
2、零拷贝
实现方法1:利用直接I/O
实现方法2:利用内存映射文件
实现方式2:利用零拷贝技术
一、缓冲I/O和直接I/O
理解缓冲I/O和直接I/O,先搞清以下几个概念:
1、应用程序内存
通常是指在代码中通过 malloc/free、new/delete等分配出来的内存。
2、用户缓冲区
用户进程通过系统调用访问系统资源的时候,需要切换到内核态,而这对应一些特殊的堆栈和内存环境,必须在系统调用前建 立好。而在系统调用结束后,cpu会从核心模式切回到用户模式,而堆栈又必须恢复成用户进程的上下文。而这种切换就会有大量的耗时。
你看一些程序在读取文件时,会先申请一块内存数组,称为buffer,然后每次调用read,读取设定字节长度的数据,写入buffer。(用较小的次数填满buffer)。之后的程序都是从buffer中获取数据,当buffer使用完后,在进行下一次调用,填充buffer。所以说:用户缓冲区的目的是为了减少系统调用次数,从而降低操作系统在用户态与核心态切换所耗费的时间。除了在进程中设计缓冲区,内核也有自己的缓冲区。
比如在C语言的FILE结构体里面的buffer。FILE结构体的定义如下,可以看到里面有定义的buffer
typedef struct {short level;short token;short bsize;char fd;unsigned flags;unsigned char hold;unsigned char *buffer;unsigned char * curp;unsigned istemp;
}FILE;
3、内核缓冲区
Linux操作系统的Page Cache。为了加快磁盘的I/O,Linux系统会把磁盘上的数据以Page 为单位缓存在操作系统的内存里,这里的Page是Linux系统定义的一个逻辑概念,一个Page一般为4K。
对于缓冲I/O,一个读操作有3次数据拷贝,一个写操作,有反向的3次数据拷贝:
- 读:磁盘 ——> 内核缓冲区 ——> 用户缓冲区 ——> 应用程序内存;
- 写:应用程序内存 ——> 用户缓冲区 ——>内核缓冲区 ——> 磁盘
对于直接I/O,一个读操作会有2次数据拷贝,一个写操作,有反向的2次数据拷贝
- 读:磁盘 ——> 内核缓冲区 ——> 应用程序内存
- 写:应用程序内存 ——> 内核缓冲区 ——> 磁盘
所以,所谓的“直接I/O”,其中直接的意思是指没有用户级的缓冲区,但操作系统本身的缓冲还是有的。
缓冲I/O和直接I/O两者对比如下图所示:
二、内存映射文件与零拷贝
1、内存映射文件
相比于直接I/O,内存映射文件往前更近了一步,当用户空间不再有物理内存,直接拿应用程序的逻辑内存地址映射到Linux操作系统内核缓冲区,应用程序虽然读写是自己的内存,但这个内存只是一个“逻辑地址”,实际读写的内存是内核缓冲区!
如:Java中的 MappedByteBuffer类实现的就是内存映射文件
数据拷贝次数从缓冲I/O的3次,到直接I/O的2次,再到内存映射文件,变成了1次。
- 读:磁盘 ——> 内核缓冲区
- 写: 内核缓冲区 ——> 磁盘。
2、零拷贝
零拷贝(Zero Copy)是提升I/O效率的一大利器,熟悉Kafka,Netty等原理的都知道,其实现原理就是通过零拷贝技术来实现读写性能的。
实现方法1:利用直接I/O
当我们把数据发送到网络中时,如果不使用零拷贝。 伪代码:
fd1 = 打开文件描述符
fd2 = 打开Socket描述符
buffer = 应用程序内存
read(fd1, buffer) //先把数据从文件读取到应用程序内存
write(fd2, buffer) //再把应用内存中的数据写入到网络中发出
如下图所示:整个文件会有4次数据拷贝,读文件2次,写网络2次。
磁盘 ——> 内核缓冲区 ——> 应用程序内存 ——> Socket缓冲区 ——> 网络
实现方法2:利用内存映射文件
此种方式,整个过程会有3次数据拷贝,不再经过应用程序内存,直接把内核空间中从内核缓冲区拷贝到Socket缓冲区。,伪代码如下:
fd1 = 打开文件描述符
fd2 = 打开Socket描述符
buffer = 应用程序内存
mmap(fd1, buffer) //先把磁盘数据映射到buffer上
write(fd2, buffer) //再通过网络发送数据
如下图所示:
注意:在这里需要分清“映射”和“拷贝”的区别。
拷贝:是把数据从一块内存中复制到另外一块内存里;
映射:相当于只是持有了数据的一个引用(或者叫地址),数据本身只有1分。
实现方式2:利用零拷贝技术
如果使用零拷贝,可能连内核缓冲区到Socket缓冲区的拷贝也省略了。在内核缓冲区和Socket缓冲区之间并没有做数据拷贝,只是一个地址的映射,底层的网卡驱动程序要读去数据并发送到网络的时候,看似读取的是Socket缓冲区的数据,但实际上直接读的是内核缓冲区的数据。
在这里,我们看到虽然叫零拷贝,实际是2次数据拷贝,1次是从磁盘到内核缓冲区,1次是从内核缓冲区到网络。之所以叫零拷贝,是从内存的角度来看的,数据在内存中没有发生过数据拷贝,只是在内存和I/O之间传输。
说明:对于把文件数据发送到网络的场景,直接I/O、内存映射文件、零拷贝对应的数据拷贝次数分别是4次、3次、2次,内存拷贝次数分别是2次、1次、0次。
参考资料 《软件架构设计——大型网站技术架构与业务架构融合之道》
更纯洁的个人博客
搞懂零拷贝这一篇文章就够了相关推荐
- 架构师必须搞懂DNS,一篇文章就够了。
转载自 架构师必须搞懂DNS,一篇文章就够了. 概念 DNS,全称Domain Name System,即域名系统,搞清楚,它不是DNF地下城与勇士. DNS是怎么来的,我们知道要访问一个服务器的资源 ...
- 五年程序员是如何玩转闲鱼无货源的,只看这一篇文章就够了
今天的内容方向主要是基础篇-进阶篇 ,优化了一下操作方法,尽量细化,让你看完这篇内容之后从入门到大神. 基础篇: 注册这些基础的之前说过,这次就不说了,这次说下如何养号. 完善个人资料(头像.昵称.简 ...
- Android:学习AIDL,这一篇文章就够了(下)
前言 上一篇博文介绍了关于AIDL是什么,为什么我们需要AIDL,AIDL的语法以及如何使用AIDL等方面的知识,这一篇博文将顺着上一篇的思路往下走,接着介绍关于AIDL的一些更加深入的知识.强烈建议 ...
- 全面认识MOS管,一篇文章就够了
基础知识中 MOS 部分迟迟未整理,实际分享的电路中大部分常用电路都用到了MOS管, 今天势必要来一篇文章,彻底掌握mos管! ...更新:为什么常在MOS管GS并联电阻? ...更新:为什么要在MO ...
- MySQL优化-一篇文章就够了(转发加收藏吧)
关注我,一个仍存梦想的屌丝程序员,每天为你分享高质量编程博客. 回复 "代金券" 免费获取腾讯云和阿里云代金券 前言 说起MySQL的查询优化,相信大家收藏了一堆:不能使用SEL ...
- 学习使用 MATLAB 数学建模一篇文章就够了
学习中,随着学习的深入会不断补充内容,欢迎大家一起学习数学建模知识,有什么问题,大家可以评论,一起讨论学习. 需要LaTeX 数学建模模板和我收集的一些数学建模资料的可以评论留下邮箱,与君共勉 !!! ...
- 学习 MongoDB 一篇文章就够了(珍藏版)
文章目录 一.学习目录 二.扩展目录 一.学习目录 认识 MongoDB 一篇文章就够了 Windows平台安装MongoDB教程 Linux 上安装 MongoDB windows 安装 Mongo ...
- 集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(离线)
原址 集成Android免费语音合成功能(在线.离线.离在线融合),有这一篇文章就够了(在线) 集成Android免费语音合成功能(在线.离线.离在线融合),有这一篇文章就够了(离在线融合) ...
- 全面认识二极管,一篇文章就够了
电子设计基础元器件 二极管,小小二极管,大大用途. ... 矜辰所致 目录 前言 一.二极管基础知识 1.1 什么是二极管 1.2 二极管的组成 1.3 二极管的原理 二.二极管特性 2.1 伏安特性 ...
最新文章
- 搭建Hadoop集群步骤
- 《预训练周刊》第36期: 谷歌提出梯度最大化增长方法GradMax
- 虚拟机复制后需要改什么_网站改版后为什么需要每月运营维护?
- js判断是安卓手机还是ios
- 关于 SAP 电商云 Spartacus UI package.json 中的 sass 依赖
- HTML5学习笔记简明版(4):新元素之video,audio,meter,datalist,keygen,output
- 如何进入指定文件目录_Python如何遍历操作指定文件目录下的全部Excel文件?
- UIMenuController在label中的使用
- PHP获取当前文件路径,上层目录路径
- oracle 获得表字段名,注释等的sql语句 .
- [原]批量删除VSS产生的scc文件
- 如何在CSDN上删除博客、删除自己上传的资源
- RichEdit控件设置默认字体时只对中文起作用,对英文不起作用的解决办法
- 兼容所有浏览器的Web打印控件的设计方案
- Android下如何与读卡器进行交互
- 【图像去噪】基于matlab自适应中值滤波图像去噪【含Matlab 1156期】
- AutoConfig工具使用指南
- 你想要的宏基因组-微生物组知识全在这(1908)
- TDSQL:腾讯金融级分布式数据库解决方案
- 基于K8S的OpenStack部署实践
热门文章
- 遗传算法基本简介及改进方向
- Azure 深入浅出[3]: 如何在MS Visio里面画专业的Azure技术架构图?
- Lua(一)——Lua介绍
- 【LSSVM回归预测】基于matlab麻雀算法优化LSSVM回归预测【含Matlab源码 1128期】
- Ubantu20.04使用gcc9.3.0安装Nvidia显卡驱动遇到的问题
- 计算机专业暑假计划,考研计算机:最适合复习的暑假黄金期来了
- zzuli OJ 1086: ASCII码排序(多实例测试)
- Linux下xl710网卡驱动,CentOS 6.x 系统安装+网卡驱动安装(Realtek PCIe GBE Family Controller for Linux)...
- 测U盘实际容量 (缩水U盘、扩容盘、假U盘)
- 【案例】前端对接LED设备发送指令