缓冲IO

在介绍缓冲IO之前需要先了解一下常用的机械硬盘的原理与特点

一个机械硬盘中装有多个盘片

每个盘片上有多个同心圆(磁道)

每个同心圆又由多个弧(扇区)组成,每个弧上都记录了等量的数据(比方说512byte)

如果发起一个随机读写请求,磁头需要先找到对应的磁道,然后等待对应的扇区旋转到磁头正下方才能开始读取数据(民用机械硬盘的转速一般在5400或者7200RPM,工业界倒是经常使用10000RPM的机械硬盘。但是它们的寻道时间大概都在几ms到十几ms左右)

机械硬盘的顺序读写很快(一般在100-200MB/s),但是随机读写很慢(寻道时间在十几ms,导致随机读写的iops只有几十)

假定我们不做任何额外的优化处理,在用户发起读数据请求的时候,直接调用硬盘驱动读取磁盘数据并返回

设想一个场景:循环调用read方法读取文件,但是每次只读取较少的数据(比方说每次只读一个byte)。那么每次read请求都对应于一次对磁盘的随机读写(两次读请求之前需要重新寻道),也就是说read操作的tps只有几十。

也就是说此时磁盘占用率为100%,但是只能提供不到100byte/s的数据读取率,这显然是不可接受的。

Linux对此有个很简单的优化,就是在内核中维护一块缓冲区(buffer cache),在用户第一次调用read读取数据的时候,无论用户想要读取的数据有多小,都会一次性从磁盘中加载一段数据放到缓冲区中,这样用户下一次调用read方法的时候可以直接从缓冲区中返回数据,不用再次访问磁盘了。

write方法也是同理,用户写入的数据不是直接落盘,而是先写到kernel中的缓冲区里,按照一定的策略批量刷盘。当然也可以调用flush方法强制将缓存区的数据落盘。

这个优化极大的提高了顺序读写的效率。由于直接读写的是kernel中的缓冲区而不是磁盘,这种IO被称为缓冲IO。

直接IO

一般来说,上面介绍的缓冲IO已经足够应付日常需求了。但是像数据库这种极度依赖IO的应用程序,为了追求极致的性能,往往更加愿意自己直接操作磁盘。

直接IO可以直接将数据从磁盘复制到用户空间,或者将数据从用户空间写到磁盘,减少了kernel中的缓冲区这一环节,这是直接IO可以提高性能的原理。

但是如果用得不好就悲剧了,所以直接IO只在少数场景下使用。

内存映射

先给出mmap的官方文档

mmap方法会返回一个void *类型的指针ptr,它指向进程逻辑空间中的一个地址。

后续如果想要读写文件,无需调用read/write方法, 而是直接操作这个ptr指针即可。

用户试图向ptr指针指向的空间读写数据时,由于MMU无法在物理内存中找到对应的地址,会触发一次缺页中断,OS会去硬盘中找到对应的数据并复制到内存中,然后用户就能正常完成读写操作了。这个过程是由操作系统自动完成的。

为什么说内存映射效率比缓冲IO要高?

我们回忆一下缓冲IO的工作流程:

1. 用户调用read方法

2. 调用系统调用,触发中断,进程从用户态进入内核态

3. 从硬盘中读取数据并复制到kernel缓冲区

4. 将数据从kernel缓存区复制到用户提供的byte数组中

5. 进程从内核态返回到用户态

完成

从上面的流程中我们可以看到,调用一次read方法,最多可能会引起两次用户态与内核态之间的切换,以及两次数据复制

而内存映射呢?

1. 用户试图访问ptr指向的数据

2. MMU解析失败,触发缺页中断,程序从用户态进入到内核态

3. 从硬盘中读取数据并复制到进程空间中ptr指向的逻辑空间里

4. 进程从内核态返回到用户态

完成

可以看出,试图访问内存映射文件,最多可能会引起两次用户态与内核态之间的切换,以及一次数据复制

也就是说,内存映射与缓冲IO相比,可以节省数据复制带来的开销,因此效率较高。

参考资料

Linux 中直接 I/O 机制的介绍

内存映射文件原理探索

Java IO 学习(三)缓冲IO / 直接IO / 内存映射的更多相关文章

  1. Java开发学习(三十七)----SpringBoot多环境配置及配置文件分类

    一.多环境配置 在工作中,对于开发环境.测试环境.生产环境的配置肯定都不相同,比如我们开发阶段会在自己的电脑上安装 mysql ,连接自己电脑上的 mysql 即可,但是项目开发完毕后要上线就需要该配 ...

  2. Java开发学习(三十六)----SpringBoot三种配置文件解析

    一. 配置文件格式 我们现在启动服务器默认的端口号是 8080,访问路径可以书写为 http://localhost:8080/books/1 在线上环境我们还是希望将端口号改为 80,这样在访问的时 ...

  3. Java NIO学习笔记九 NIO与IO对比

    Java NIO与IO Java nio 和io 到底有什么区别,以及什么时候使用nio和io,本文做一个比较. Java NIO和IO之间的主要区别 下表总结了Java NIO和IO之间的主要区别, ...

  4. Java虚拟机学习(1):体系结构 内存模型

    一:Java技术体系模块图 Java技术体系模块图 二:JVM内存区域模型 1.方法区 也称"永久代" ."非堆",  它用于存储虚拟机加载的类信息.常量.静态 ...

  5. Java开发学习(二十四)----SpringMVC设置请求映射路径

    一.环境准备 创建一个Web的Maven项目 参考Java开发学习(二十三)----SpringMVC入门案例.工作流程解析及设置bean加载控制中环境准备 pom.xml添加Spring依赖 < ...

  6. Java IO学习--(三)通道

    Java IO中的管道为运行在同一个JVM中的两个线程提供了通信的能力.所以管道也可以作为数据源以及目标媒介. 你不能利用管道与不同的JVM中的线程通信(不同的进程).在概念上,Java的管道不同于U ...

  7. java 多线程学习笔记(二) -- IO密集型任务

    IO密集型是指对IO操作较多的任务.下面以查询一些股票价格任务为例: YahooFinance.java public class YahooFinance { public static doubl ...

  8. Linux非阻塞IO(三)非阻塞IO中缓冲区Buffer的实现

    本文我们来实现回射服务器的Buffer.   Buffer的实现   上节提到了非阻塞IO必须具备Buffer.再次将Buffer的设计描述一下: 这里必须补充一点,writeIndex指向空闲空间的 ...

  9. linux io 学习笔记(03)---共享内存,信号灯,消息队列

    system V IPC 1)消息队列 2)共享内存 3)信号灯(信号量集) 1.消息队列. ipcs -q 查看系统中使用消息队列的情况 ipcrm -q +msqid 删除消息队列 消息队列工作原 ...

  10. Java开发学习(三十五)----SpringBoot快速入门及起步依赖解析

    一.SpringBoot简介 SpringBoot 是由 Pivotal 团队提供的全新框架,其设计目的是用来简化 Spring 应用的初始搭建以及开发过程. 使用了 Spring 框架后已经简化了我 ...

随机推荐

  1. Memory loss【记忆缺失】

    Memory Loss Losing your ability to think and remember is pretty scary. We know the risk of dementia ...

  2. input type=file输入框

    <div class="row"> <!--选择图片按钮--> <div class="col-xs-12" align=&quo ...

  3. BZOJ 3420: Poi2013 Triumphal arch

    二分答案 第二个人不会走回头路 那么F[i]表示在i的子树内(不包括i)所需要的额外步数 F[1]==0表示mid可行 k可能为0 #include<cstdio> #include< ...

  4. Python 拓展之迭代器

    写在之前 今天来讲讲「迭代器」的内容,其实已经拖了好多天了,感觉再不写就要忘记了.「迭代」相信对你来说已经不陌生了,我前面曾经专门用一篇文章来讲,如果你已经没有什么印象的话,就再点进去看看(零基础学习 ...

  5. Leetcode 500.键盘行

    键盘行 给定一个单词列表,只返回可以使用在键盘同一行的字母打印出来的单词.键盘如下图所示. 示例: 输入: ["Hello", "Alaska", " ...

  6. zookeeper 下载安装

    下载:wget https://www-us.apache.org/dist/zookeeper/zookeeper-3.4.13/zookeeper-3.4.13.tar.gz 解压:tar -zx ...

  7. log4net实现多实例记录

    原文地址:实现多个LOG4NET日志记录器实例 本文内容为摘抄,请查看原文. 对于.NET Framework开发者来说,使用Log4Net进行日志记录是非常方便的,通常只要写好配置文件和简单的编码就 ...

  8. 用最优方法从LinkedList列表中删除重复元素

    用运行速度最优的方法从LinkedList列表里删除重复的元素,例如A->B->BB->B->C,返回A->B->BB->C. 考试的时候没完全想明白,考完又 ...

  9. 用Vundle管理Vim插件

    作为程序员,一个好用的Vim,是极其重要的,而插件能够使原本功能羸弱的Vim变得像其他功能强大的IDE一样好用.然而下载.配置插件的过程比较繁琐,大家往往需要自己进行下载/配置等操作,如果还涉及到更新 ...

  10. 【bzoj3944/bzoj4805】Sum/欧拉函数求和 杜教筛

    bzoj3944 题目描述 输入 一共T+1行 第1行为数据组数T(T<=10) 第2~T+1行每行一个非负整数N,代表一组询问 输出 一共T行,每行两个用空格分隔的数ans1,ans2 样例输 ...