美文网首页
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 / 内存映射

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