缓冲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. U10783 名字被和谐了

    U10783 名字被和谐了 题目背景 众所周知,我们称g是a的约数,当且仅当g是正数且a mod g = 0. 众所周知,若g既是a的约数也是b的约数,我们称g是a.b的一个公约数. 众所周知,a.b ...

  2. 1 - smart(Maven:Package,Install,&,Log4j2)

    mvn package 时,增加如下命令-Dmaven.test.skip=true 则表示package打包时,不执行也不编译测试用例,mvn package -Dmaven.test.skip=t ...

  3. 图文教程:为认证考试搭建Hyper-V家庭实验室

    [TechTarget中国原创] 在过去20年里,我已经帮助成千上万人准备他们的IT认证考试.虽然有很多方法通过技术来获得经验,组建一个Hyper-V家庭实验室是个利用不同应用程序来获得经验的廉价并有 ...

  4. python深浅拷贝以及数据在内存中储存方法

    要搞懂深浅拷贝,首先要明白数据在内存里的储存方法. 一个变量的储存,首先是变量名加上储存内容的ID,通过ID去找到变量名所对应的内容, 当我们对数据进行赋值时,其实是把内容的整体地址赋给别的变量名(相 ...

  5. C# 调试之 Debug.WriteLine()、Trace.WriteLine()

    Trace 类 和 Debug 类的区别在于,Trace 类会同时在 Debug.Release 模式下起作用,而 Debug 只作用在 Debug 模式下. 区别: 1. 输出跟踪信息 Trace. ...

  6. OOP的三大特性------封装、继承、多态

    封装 1.<1>类背后隐藏的思想是数据抽象和封装 <2>信息隐藏,隐藏对象的实现细节,不让外部直接访问到 将数据成员和成员函数一起包装到一个单元里,单元以类的形式实现 < ...

  7. 使用 Python 获取 Linux 系统信息

    探索platform模块 platform模块在标准库中,它有很多运行我们获得众多系统信息的函数.让我们运行Python解释器来探索它们中的一些函数,那就从platform.uname()函数开始吧: ...

  8. ReentrantLock学习笔记

    参考:https://www.jianshu.com/p/4358b1466ec9 前言: 先来想象一个场景:手把手的进行锁获取和释放,先获得锁A,然后再获取锁B,当获取锁B后释放锁A同时获取锁C,当 ...

  9. httpClient 保持session

    import org.apache.commons.httpclient.Cookie; import org.apache.commons.httpclient.HttpClient; import ...

  10. CCC2019游记

    好吧其实是清华游记,$CCC2019$ 在中国只有北京和天津举办,要选去加拿大的人很少,估计是最近两国关系有点紧张的缘故吧 但实际上是某些已经被清华钦点的人去预览一下他们未来的栖息所 $13:30$ ...