美文网首页
Java IO 学习(三)缓冲IO / 直接IO / 内存映射

Java IO 学习(三)缓冲IO / 直接IO / 内存映射

作者: taj3991 | 来源:发表于2020-02-21 18:02 被阅读0次

缓冲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的官方文档

   #include <sys/mman.h>

       void *mmap(void *addr, size_t length, int prot, int flags,
                  int fd, off_t offset);
       int munmap(void *addr, size_t length);

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

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

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

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

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

    1. 用户调用read方法
    1. 调用系统调用,触发中断,进程从用户态进入内核态
  • 3.从硬盘中读取数据并复制到kernel缓冲区
    1. 将数据从kernel缓存区复制到用户提供的byte数组中
    1. 进程从内核态返回到用户态
    1. 完成
      从上面的流程中我们可以看到,调用一次read方法,最多可能会引起两次用户态与内核态之间的切换,以及两次数据复制.

而内存映射呢?

    1. 用户试图访问ptr指向的数据
    1. MMU解析失败,触发缺页中断,程序从用户态进入到内核态
    1. 从硬盘中读取数据并复制到进程空间中ptr指向的逻辑空间里
    1. 进程从内核态返回到用户态
    1. 完成

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

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

MMU

MMU是Memory Management Unit的缩写,中文名是内存管理单元,有时称作分页内存管理单元(英语:paged memory management unit,缩写为PMMU)。它是一种负责处理中央处理器(CPU)的内存访问请求的计算机硬件。它的功能包括虚拟地址到物理地址的转换(即虚拟内存管理)、内存保护、中央处理器高速缓存的控制,在较为简单的计算机体系结构中,负责总线的仲裁以及存储体切换(bank switching,尤其是在8位的系统上)。

原文

https://www.cnblogs.com/stevenczp/p/7496089.html

相关文章

  • Java IO 学习(三)缓冲IO / 直接IO / 内存映射

    缓冲IO 在介绍缓冲IO之前需要先了解一下常用的机械硬盘的原理与特点 一个机械硬盘中装有多个盘片 每个盘片上有多个...

  • 软件架构设计-操作系统

    操作系统 直接IO与缓冲IO 缓冲io又称作标准I/O,大多数文件系统的默认IO操作都是缓冲IO。在linux的缓...

  • java-nio学习之java io比较

    java io 基本介绍 java nio和io区别 面向流与面向缓冲 IO是面向流的,NIO是面向缓冲区的。 J...

  • 嵌入式面试题

    内存管理MMU的作用? 内存分配和回收 内存保护 内存扩充 地址映射 异步IO和同步IO的区别? 如果是同步IO,...

  • Java的IO操作

    Java的IO操作分为磁盘IO和内存流IO。 1、磁盘IO:FileInputStream和FileOutputS...

  • java基础专题:4. 标准IO,直接IO,内存映射

    详见链接https://www.cnblogs.com/sunsky303/p/8962628.html 1.标准...

  • Java的IO & NIO

    IO流学习总结一Java IO,硬骨头也能变软二java IO体系的学习总结三Java IO面试题 NIO与AIO...

  • IO、NIO

    IO、NIO Java NIO和IO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO...

  • 01Nio-Buffer

    缓冲区的使用 Java IO和NIO之间第一个最大的区别是,IO是面向流的,NIO是面向缓冲区的。 Java IO...

  • 2019-04-30——Java NOI

    经典java IO库 对于经典的IO除了Buffered开头的类,其他均没有加缓冲区,除非手动添加缓冲区 经典io...

网友评论

      本文标题:Java IO 学习(三)缓冲IO / 直接IO / 内存映射

      本文链接:https://www.haomeiwen.com/subject/tifhqhtx.html