两个缓冲空间:kernel buffer和io buffer

先看一张图,稍后将围绕这张图展开描述。图中的fd table、open file table以及两个inode table都可以不用理解,只需要知道它们体现出来的文件描述符和磁盘文件之间的对应关系:文件描述符fd(例如图中的fd=3)是对应磁盘上文件的。

在Linux下,我们经常会在IO操作时不可避免的涉及到文件描述符,因为Linux下的所有IO操作都是通过文件描述符来完成的。但是,文件描述符是一个非常底层的概念,通过它操作的数据,都是二进制数据,所以通过文件描述符完成IO的模式通常也称为裸IO(Raw IO)。而且,直接通过底层的文件描述符进行编程会比较麻烦,因为是二进制数据,它缺少很多功能,比如无法指定编码,无法指定换行符(换行符有多种:\n、\n\r、\r)等等。注意fd是用户空间的,它仅仅是一个数值而已,并不是想象中感觉比较底层就在内核空间。

所以,现代高级语言(比如C、Python、Java、Golang)都提供了比文件描述符更高一层次的标准IO库,比如C的标准IO库是stdio,Python的标准IO库是IO模块,等等。使用这些标准IO库中的函数进行IO操作时,都会使用比文件描述符更高一层次的对象,例如C中称为IO流(io stream),其它面向对象的语言中一般称为IO对象,为了方便说明,这里统称为IO对象。上图中的F就是文件对象。

标准IO库可以看作是文件描述符的更高层次的封装,提供了比文件描述符操作IO更多的功能。例如,可以在IO对象上指定编码、指定换行符,此外还在用户空间提供了一个标准IO库的缓冲空间,通常可称为stdio bufferIO buffer,而这些功能在文件描述符上都是没有的。另外,标准IO库既然是高层封装,当然也会提供用户不使用这些功能(比如不使用IO Buffer),而是直接使用文件描述符,那么这时候的文件对象就相当于是文件描述符了,这时候的IO操作模式也就是裸IO模式。

所有从硬件读取或写入到硬件的数据,默认都会经过操作系统维护的这个Kernel Buffer。正如上图中描述的是读数据过程。

例如,cat进程想要读取a.log文件,cat进程是用户空间进程,它自身没有权限打开文件以及读文件数据,它只能通过系统调用的方式陷入内核,请求操作系统帮助读取数据,操作系统读取数据后会将数据放入到page cache(刚才已说明,对于普通文件维护的Kernel buffer称为page cache或buffer cache)。然后还要将内核空间page cache中的数据拷贝到用户空间的IO Buffer缓冲空间(因为cat程序的源代码中使用了标准IO库stdio),然后cat进程从自己的IO Buffer中读取数据。这就是整个读数据的过程。

需要注意的是,虽然这两段缓冲空间都在内存中,但仍然有拷贝操作,因为内核的内存空间和用户进程的虚拟内存空间是隔离的,用户空间进程没有权限访问到内核空间的内存,但是内核具有最高权限,允许访问任何内存地址。换句话说,在将Kernel Buffer的数据拷贝到IO Buffer空间的过程中,需要陷入到内核,OS需要掌控CPU。

此外,Linux也提供了所谓的直接IO模式,只需使用一个称为O_DIRECT的标记即可,这时会绕过Kernel Buffer,直接将硬件数据拷贝到用户空间。虽然看上去直接IO少了一个层次的参与感觉性能会更优秀,但实际上并非如此,操作系统为内核缓冲空间做了非常多的优化,使得并不会因此而降低性能。最典型且常见的一个优化是预读功能,它表示在读数据时,会比所请求要读取的数据量多读一点放入到Kernel Buffer,这样在下次读取接下来的一段数据时可以直接从Kernel Buffer中取数据,而无需再和硬件IO交互。所以,使用直接IO模式的场景是非常少的,一般只会在自带了完整缓冲模型的大型软件(比如数据库系统)上可能会使用直接IO模式。

上面所描述的都是读操作,关于写操作,这里不再多花篇幅去描述,整体过程和读是类似的,都会经过IO Buffer和Kernel Buffer,只是其中一些细节有所不同,如果感兴趣,可以阅读《Linux/Unix系统编程手册》的第13章。

每天3分钟操作系统修炼秘籍(13):两个缓冲空间Kernel Buffer和IO Buffer的更多相关文章

  1. 每天3分钟操作系统修炼秘籍(14):IO操作和DMA、RDMA

    点我查看秘籍连载 I/O操作和DMA.RDMA 用户进程想要执行IO操作时(例如想要读磁盘数据.向磁盘写数据.读键盘的输入等等),由于用户进程工作在用户模式下,它没有执行这些操作的权限,只能通过发起对 ...

  2. 每天3分钟操作系统修炼秘籍(12):OOM和swap分区

    点我查看秘籍连载 OOM和swap分区 进程的虚拟内存空间是映射到整个物理内存空间的,所以在进程自身看来它拥有了整个物理内存,它也能使用整个物理内存,只需在使用的时候请求操作系统帮忙分配更多空间即可. ...

  3. 每天3分钟操作系统修炼秘籍(6):Idle进程

    点我查看秘籍连载 CPU的归属:Idle进程 操作系统并不总是繁忙.例如个人PC上任务比较轻,多数时候都无法充分利用CPU,导致CPU处于空闲状态.但CPU既然通电了,它就得运行,那么在它没有任务需要 ...

  4. Vim修炼秘籍之语法篇

    前言 少年,我看你骨骼精奇,是万中无一的武学奇才,维护世界和平就靠你了,我这有本秘籍<Vim修炼秘籍>,见与你有缘,就十块卖给你了! 如果你是一名 Vimer,那么恭喜你,你的 Vim 技 ...

  5. MySQL Innodb的两种表空间方式

    要说表空间,MySQL的表空间管理远远说不上完善.换句话说,事实上MySQL根本没有真正意义上的表空间管理.MySQL的Innodb包含两种表空间文件模式,默认的共享表空间和每个表分离的独立表空间.只 ...

  6. 在编写wpf界面时候中出现如下错误: 类型引用不明确。至少有两个名称空间(“System.Windows”和“System.Windows”)中已出现名为“VisualStateManager”的类型。请考虑调整程序集 XmlnsDefinition 特性。

    wpf中类型引用不明确.至少有两个名称空间(“System.Windows”和“System.Windows”)中已出现名为“VisualState 你是不是用了WPFToolKit?如果是的,那原因 ...

  7. java io系列13之 BufferedOutputStream(缓冲输出流)的认知、源码和示例

    本章内容包括3个部分:BufferedOutputStream介绍,BufferedOutputStream源码,以及BufferedOutputStream使用示例. 转载请注明出处:http:// ...

  8. 9.11排序与查找(一)——给定两个排序后的数组A和B,当中A的末端有足够的缓冲空间容纳B。将B合并入A并排序

    /**  * 功能:给定两个排序后的数组A和B,当中A的末端有足够的缓冲空间容纳B.将B合并入A并排序. */ /** * 问题:假设将元素插入数组A的前端,就必须将原有的元素向后移动,以腾出空间. ...

  9. 操作系统开发系列—13.g.操作系统的系统调用 ●

    在我们的操作系统中,已经存在的3个进程是运行在ring1上的,它们已经不能任意地使用某些指令,不能访问某些权限更高的内存区域,但如果一项任务需要这些使用指令或者内存区域时,只能通过系统调用来实现,它是 ...

随机推荐

  1. 加密解密 之base系列编码

    Base16 Base16编码使用16个ASCII可打印字符(数字0-9和字母A-F)对任意字节数据进行编码.Base16先获取输入字符串每个字节的二进制值(不足8比特在高位补0),然后将其串联进来, ...

  2. PhantomJS not found on PATH

    使用vue-cli创建项目后,npm init常出现以下问题:PhantomJS not found on PATH 这是因为文件phantomjs-2.1.1-windows.zip过大,网络不好容 ...

  3. Ubuntu php + apache

    Ubuntu 环境: 问题1: apache 不能解析 *.php 文件 安装apache的扩展模块 :  apt-get install libapache2-mod-php 问题2 : 客户端访问 ...

  4. PHP get_class_vars 和 (array)

    <?php class Girl { public $id = 1; public $name = 'zhy'; } $start = microtime(TRUE); var_dump(get ...

  5. (20)ASP.NET Core EF创建模型(必需属性和可选属性、最大长度、并发标记、阴影属性)

    1.必需和可选属性 如果实体属性可以包含null,则将其视为可选.如果属性的有效值不可以包含null,则将其视为必需属性.映射到关系数据库架构时,必需的属性将创建为不可为null的列,而可选属性则创建 ...

  6. NServiceBus+RabbitMQ开发分布式应用

    前言      NServiceBus提供了8种传输管道组件,分别是Learning.MSMQ.Azure Service Bus.Azure Service Bus (Legacy).Azure S ...

  7. Go语言系列开发之延迟调用和作用域

    Hello,各位小伙伴大家好,我是小栈君,最近一段时间我们将继续分享关于go语言基础系列,当然后期小栈君已经在筹划关于java.Python,数据分析.人工智能和大数据等相关系列文章.希望能和大家一起 ...

  8. Spring Boot2 系列教程(十六)定时任务的两种实现方式

    在 Spring + SpringMVC 环境中,一般来说,要实现定时任务,我们有两中方案,一种是使用 Spring 自带的定时任务处理器 @Scheduled 注解,另一种就是使用第三方框架 Qua ...

  9. [洛谷P2396]yyy loves Maths VII $\&$ [CF327E]Axis Walking

    这道题是一个状压动归题.子集生成,每一位表示是否选择了第$i$个数. 转移:$f[S] = \sum f[S-\{x\}]$且$x\in S$,当该子集所有元素的和为$b_1$或$b_2$时不转移. ...

  10. 微信小程序--获取用户地理位置名称(无须用户授权)的方法

    准备 1.在http://lbs.qq.com/网站申请key 2.在微信小程序后台把apis.map.qq.com添加进request合法域名 效果 添加封装 /** * 发起网络请求 * @par ...