Java NIO笔记之IO基础概念

来源:互联网 发布:备考注册会计师 知乎 编辑:程序博客网 时间:2024/06/05 07:19

1.缓冲区
缓冲区是所有IO的基础,”输入/输出”就是将数据移进或移除缓冲区。进程IO操作的执行也是向操作系统发送请求,让它要么将缓冲区的数据排干(写),要么将缓冲区的填满数据(读)。
这里写图片描述
图 1-1 简单描述了数据从外部磁盘向运行中的进程的内存区域移动的过程。进程使用 read()系统调用,要求其缓冲区被填满。内核随即向磁盘控制硬件发出命令,要求其从磁盘读取数据。磁盘控制器把数据直接写入内核内存缓冲区,这一步通过 DMA 完成,无需主CPU协助。一旦磁盘控制器把缓冲区装满,内核即把数据从内核空间的临时缓冲区拷贝到进程执行read()调用时指定的缓冲区。
2.用户空间和系统空间
这里写图片描述
  用户空间是常规进程所在区域。JVM 就是常规进程,驻守于用户空间。用户空间是非特权区域:比如,在该区域执行的代码就不能直接访问硬件设备。
  内核空间是操作系统所在区域。内核代码有特别的权力:它能与设备控制器通讯,控制着用户区域进程的运行状态,等等。最重要的是,所有I/O都直接或间接通过内核空间。

  当进程请求I/O操作的时候,它执行一个系统调用(有时称为陷阱)将控制权移交给内核。C/C++程序员所熟知的底层函数open()、read()、write()和close()要做的无非就是建立和执行适当的系统调用。当内核以这种方式被调用,它随即采取任何必要步骤,找到进程所需数据,并把数据传送到用户空间内的指定缓冲区。内核试图对数据进行高速缓存或预读取,因此进程所需数据可能已经在内核空间里了。如果是这样,该数据只需简单地拷贝出来即可。如果数据不在内核空间,则进程被挂起,内核着手把数据读进内存。

  您可能会觉得,把数据从内核空间拷贝到用户空间似乎有些多余。为什么不直接让磁盘控制器把数据送到用户空间的缓冲区呢?
这样做有几个问题。
首先,硬件通常不能直接访问用户空间 其次,像磁盘这样基于块存储的硬件设备操作的是固定大小的数据块,而用户进程请求的可能是任意大小的或非对齐的数据块。在数据往来于用户空间与存储设备的过程中,内核负责数据的分解、再组合工作,因此充当着中间人的角色。
3.虚拟内存
虚拟内存意为使用虚假(或虚拟)地址取代物理(硬件RAM)内存地址
(1)一个以上的虚拟地址可指向同一个物理内存地址.
(2)虚拟内存空间可大于实际可用的硬件内存.
  设备控制器不能通过DMA直接存储到用户空间,但通过利用上面提到的第一项,则可以达到相同效果。把内核空间地址与用户空间的虚拟地址映射到同一个物理地址,这样,DMA 硬件(只能访问物理内存地址)就可以填充对内核与用户空间进程同时可见的缓冲区(见图1-3)。
4.内存页面调度
这里写图片描述
  为了支持虚拟内存的第二个特性(寻址空间大于物理内存),就必须进行虚拟内存分页(经常称为交换,虽然真正的交换是在进程层面完成,而非页层面)。依照该方案,虚拟内存空间的页面能够继续存在于外部磁盘存储,这样就为物理内存中的其他虚拟页面腾出了空间。从本质上说,物理内存充当了分页区的高速缓存;而所谓分页区,即从物理内存置换出来,转而存储于磁盘上的内存页面。
  现代CPU包含一个称为内存管理单元(MMU)的子系统,逻辑上位于CPU与物理内存之间。该设备包含虚拟地址向物理内存地址转换时所需映射信息。当CPU引用某内存地址时,MMU负责确定该地址所在页(往往通过对地址值进行移位或屏蔽位操作实现),并将虚拟页号转换为物理页号(这一步由硬件完成,速度极快)。如果当前不存在与该虚拟页形成有效映射的物理内存页,MMU会向CPU 提交一个页错误。
5.文件IO
  文件系统是更高层次的抽象,是安排、解释磁盘(或其他随机存取块设备)数据的一种独特方式。您所写代码几乎无一例外地要与文件系统打交道,而不是直接与磁盘打交道。是文件系统定义了文件名、路径、文件、文件属性等抽象概念。
  所有I/O都是通过请求页面调度完成的。页面调度是非常底层的操作,仅发生于磁盘扇区与内存页之间的直接传输。而文件 I/O 则可以任意大小、任意定位。那么,底层的页面调度是如何转换为文件 I/O 的?
  文件系统把一连串大小一致的数据块组织到一起。有些块存储元信息,如空闲块、目录、索引等的映射,有些包含文件数据。单个文件的元信息描述了哪些块包含文件数据、数据在哪里结束、最后一次更新是什么时候,等等。
  当用户进程请求读取文件数据时,文件系统需要确定数据具体在磁盘什么位置,然后着手把相关磁盘扇区读进内存。老式的操作系统往往直接向磁盘驱动器发布命令,要求其读取所需磁盘扇区。而采用分页技术的现代操作系统则利用请求页面调度取得所需数据。
采用分页技术的操作系统执行 I/O 的全过程可总结为以下几步:
1、确定请求的数据分布在文件系统的哪些页(磁盘扇区组)。磁盘上的文件内容和元数据可能跨越多个文件系统页,而且这些页可能也不连续。
2、在内核空间分配足够数量的内存页,以容纳得到确定的文件系统页。
3、在内存页与磁盘上的文件系统页之间建立映射。
4、为每一个内存页产生页错误。
5、虚拟内存系统俘获页错误,安排页面调入,从磁盘上读取页内容,使页有效。
6、一旦页面调入操作完成,文件系统即对原始数据进行解析,取得所需文件内容或属性信息。
  需要注意的是,这些文件系统数据也会同其他内存页一样得到高速缓存。对于随后发生的 I/O请求,文件数据的部分或全部可能仍旧位于物理内存当中,无需再从磁盘读取即可重复使用。
6.映射内存文件
这里写图片描述
内存映射I/O使用文件系统建立从用户空间直到可用文件系统页的虚拟内存映射。这样做有几
个好处:
1、用户进程把文件数据当作内存,所以无需发布 read( )或 write( )系统调用。
2、当用户进程碰触到映射内存空间,页错误会自动产生,从而将文件数据从磁盘读进内存。如果用户修改了映射内存空间,相关页会自动标记为脏,随后刷新到磁盘,文件得到更新。
3、操作系统的虚拟内存子系统会对页进行智能高速缓存,自动根据系统负载进行内存管理。
4、数据总是按页对齐的,无需执行缓冲区拷贝。
5、大型文件使用映射,无需耗费大量内存,即可进行数据拷贝。
虚拟内存和磁盘 I/O 是紧密关联的,从很多方面看来,它们只是同一件事物的两面。在处理大量数据时,尤其要记得这一点。如果数据缓冲区是按页对齐的,且大小是内建页大小的倍数,那么,对大多数操作系统而言,其处理效率会大幅提升。
7.文件锁定
这里写图片描述
这里写图片描述
文件锁定有两种方式:共享的和独占的。多个共享锁可同时对同一文件区域发生作用;独占锁则不同,它要求相关区域不能有其他锁定在起作用。

参考:《Java NIO》

0 0
原创粉丝点击