目录

一、缓冲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次。

参考资料  《软件架构设计——大型网站技术架构与业务架构融合之道》

更纯洁的个人博客

搞懂零拷贝这一篇文章就够了相关推荐

  1. 架构师必须搞懂DNS,一篇文章就够了。

    转载自 架构师必须搞懂DNS,一篇文章就够了. 概念 DNS,全称Domain Name System,即域名系统,搞清楚,它不是DNF地下城与勇士. DNS是怎么来的,我们知道要访问一个服务器的资源 ...

  2. 五年程序员是如何玩转闲鱼无货源的,只看这一篇文章就够了

    今天的内容方向主要是基础篇-进阶篇 ,优化了一下操作方法,尽量细化,让你看完这篇内容之后从入门到大神. 基础篇: 注册这些基础的之前说过,这次就不说了,这次说下如何养号. 完善个人资料(头像.昵称.简 ...

  3. Android:学习AIDL,这一篇文章就够了(下)

    前言 上一篇博文介绍了关于AIDL是什么,为什么我们需要AIDL,AIDL的语法以及如何使用AIDL等方面的知识,这一篇博文将顺着上一篇的思路往下走,接着介绍关于AIDL的一些更加深入的知识.强烈建议 ...

  4. 全面认识MOS管,一篇文章就够了

    基础知识中 MOS 部分迟迟未整理,实际分享的电路中大部分常用电路都用到了MOS管, 今天势必要来一篇文章,彻底掌握mos管! ...更新:为什么常在MOS管GS并联电阻? ...更新:为什么要在MO ...

  5. MySQL优化-一篇文章就够了(转发加收藏吧)

    关注我,一个仍存梦想的屌丝程序员,每天为你分享高质量编程博客. 回复 "代金券"  免费获取腾讯云和阿里云代金券 前言 说起MySQL的查询优化,相信大家收藏了一堆:不能使用SEL ...

  6. 学习使用 MATLAB 数学建模一篇文章就够了

    学习中,随着学习的深入会不断补充内容,欢迎大家一起学习数学建模知识,有什么问题,大家可以评论,一起讨论学习. 需要LaTeX 数学建模模板和我收集的一些数学建模资料的可以评论留下邮箱,与君共勉 !!! ...

  7. 学习 MongoDB 一篇文章就够了(珍藏版)

    文章目录 一.学习目录 二.扩展目录 一.学习目录 认识 MongoDB 一篇文章就够了 Windows平台安装MongoDB教程 Linux 上安装 MongoDB windows 安装 Mongo ...

  8. 集成Android免费语音合成功能(在线、离线、离在线融合),有这一篇文章就够了(离线)

    原址 集成Android免费语音合成功能(在线.离线.离在线融合),有这一篇文章就够了(在线) 集成Android免费语音合成功能(在线.离线.离在线融合),有这一篇文章就够了(离在线融合)     ...

  9. 全面认识二极管,一篇文章就够了

    电子设计基础元器件 二极管,小小二极管,大大用途. ... 矜辰所致 目录 前言 一.二极管基础知识 1.1 什么是二极管 1.2 二极管的组成 1.3 二极管的原理 二.二极管特性 2.1 伏安特性 ...

最新文章

  1. 搭建Hadoop集群步骤
  2. 《预训练周刊》第36期: 谷歌提出梯度最大化增长方法GradMax
  3. 虚拟机复制后需要改什么_网站改版后为什么需要每月运营维护?
  4. js判断是安卓手机还是ios
  5. 关于 SAP 电商云 Spartacus UI package.json 中的 sass 依赖
  6. HTML5学习笔记简明版(4):新元素之video,audio,meter,datalist,keygen,output
  7. 如何进入指定文件目录_Python如何遍历操作指定文件目录下的全部Excel文件?
  8. UIMenuController在label中的使用
  9. PHP获取当前文件路径,上层目录路径
  10. oracle 获得表字段名,注释等的sql语句 .
  11. [原]批量删除VSS产生的scc文件
  12. 如何在CSDN上删除博客、删除自己上传的资源
  13. RichEdit控件设置默认字体时只对中文起作用,对英文不起作用的解决办法
  14. 兼容所有浏览器的Web打印控件的设计方案
  15. Android下如何与读卡器进行交互
  16. 【图像去噪】基于matlab自适应中值滤波图像去噪【含Matlab 1156期】
  17. AutoConfig工具使用指南
  18. 你想要的宏基因组-微生物组知识全在这(1908)
  19. TDSQL:腾讯金融级分布式数据库解决方案
  20. 基于K8S的OpenStack部署实践

热门文章

  1. 遗传算法基本简介及改进方向
  2. Azure 深入浅出[3]: 如何在MS Visio里面画专业的Azure技术架构图?
  3. Lua(一)——Lua介绍
  4. 【LSSVM回归预测】基于matlab麻雀算法优化LSSVM回归预测【含Matlab源码 1128期】
  5. Ubantu20.04使用gcc9.3.0安装Nvidia显卡驱动遇到的问题
  6. 计算机专业暑假计划,考研计算机:最适合复习的暑假黄金期来了
  7. zzuli OJ 1086: ASCII码排序(多实例测试)
  8. Linux下xl710网卡驱动,CentOS 6.x 系统安装+网卡驱动安装(Realtek PCIe GBE Family Controller for Linux)...
  9. 测U盘实际容量 (缩水U盘、扩容盘、假U盘)
  10. 【案例】前端对接LED设备发送指令