Java NIO系列1:从操作系统的角度剖析I/O

认识IO的本质

一、IO对性能的影响

首先来理解下IO对程序性能的影响:

Java NIO系列1:从操作系统的角度剖析I/O_第1张图片

从上面的表中可以得出的结论是:处理时间与IO时间对吞吐率的影响:把单位处理时间减半,仅能提高吞吐率2.2%。而仅仅缩短I/O延迟10%,就可使吞吐率增加9.7%;把I/O时间减半,吞吐率几乎翻番

二、理解BIO的局限性

BIO,也称为阻塞IO,是在jdk1.4之前使用的IO模型,BIO的局限可以从下面的叙述中理解:

现在大多数基于Java的应用在处理数据上的不足在于JVM对IO处理的效率。操作系统往往发送给缓冲区的数据是块数据,而JVM的BIO类则把块数据切分为一个一个字节(或者几行文本数据)进行处理,而一次数据的拷贝需要往返几个来回。所以可见传统的BIO类在处理数据的低效。当然,BIO类也可以传送大量的数据,那就是用RandomAccessFile类。而该类提高效率的关键是使用类似于操作系统的read与write系统调用。

这就是说,只要直接使用Java本地接口编写程序,那么IO的效率是不是就能提高了呢?固然,但是直接操作本地操作系统的特性会使得程序绑定于某一类的操作系统,程序无法移植。为了保持Java跨平台的特性,Sun公司推出了java.nio包。具体其实Channel类和Selector类。

IO的操作系统解释

一、缓冲区操作

IO的基础就是缓冲区,本质上将,IO也就是输入/输出,实际上是对数据在缓冲区的移入和移出。

下面这张图描绘了IO的处理处理过程:

当进程执行IO请求时,(进程属于用户空间)进程会执行一次系统调用(也称为陷进)把控制权交给内核。内核接收到请求后,如果数据不在告诉缓存中,会去寻找进程需要的数据并把数据加载到

进程指定的用户空间的缓冲区中;如果进程请求的数据已经在告诉缓存中,那么只需要把高速缓存的数据拷贝到缓冲区即可。

这个过程展示了内核作为中间角色作用,内核直接与硬件设备打交道,用户空间不能直接与硬件设备。这点的原因有两个:一是用户空间的地址都是虚拟地址(至于为什么是虚拟地址则可能需要阅读操作系统的资料了),虚拟地址必须经过转换才能访问硬件设备,这个过程是由MMU(内存管理单元)来完成的;二是为了安全

二、虚拟内存

现代操作系统都使用虚拟内存,所谓虚拟内存就是使用虚假的内存地址取代物理地址(设备地址)。

这样做的好处有两点:一是一个以上的虚拟内存地址可以指向同一个物理地址;二是虚拟内存空间可大于物理地址空间。

由于操作系统的虚拟内存使用能够页式管理方案(内存地址一页一页存放),所以采用虚拟内存后,进程对设备的操作就大大简化了,通过对内存空间的映射,用户空间与内存空间的缓冲区可以指向同一段物理内存空间,这样进程在请求数据的时候就不用在用户空间和内核空间来回拷贝数据了。

为什么虚拟内存空间可以大于物理地址空间,主要是因为进程暂时不用的页面(虚拟内存采用内存分页的方式)保存在外部磁盘,将需要的页面调入内存,原来不用的页面再被置换出去,这样就实现了虚拟内存地址空间大于物理地址空间。

虚拟内存采用内存分页后,内存地址就以页为单位进行管理。回到之前进程请求数据(也就是I/O啦)的过程,MMU会首先找到虚拟地址对应的页,然后根据虚拟页号映射到物理的内存页号(这个过程由硬件完成,速度很快)。

如果当前不存在物理页号与该虚拟页号的映射,那么会产生一个页错误。发生页错误后,进程会执行一次系统调用,从用户态陷入内核态,附带出错的虚拟地址信息,把缺失的页重新调入物理内存。因为物理内存调入的页面数往往是固定的,那么调入一个新的页面势必就会导致一个旧页面被置换出物理内存,这个被置换出去的页面如果是脏的,那么需要首先执行页面调出,将页面的内存输出到磁盘的分页区。一旦出错的页重新调入内存,MMU也会更新新的虚拟地址到物理地址的映射。

三、文件IO

文件IO不同于进程请求数据这一模型,因为文件IO需要与文件系统打交道,而本质上IO都是底层页面的调度的操作,也就是磁盘扇区与内存页面之间的交互。现在IO需要通过文件系统,那么文件系统是如何完成这个过程的转换呢?

了解操作系统的都知道,文件系统实际上的文件的高级抽象,把文件分为元数据和数据,每个文件都有元数据,元数据描述了哪些文件块包含该数据,数据在哪里开始,哪里结束以及最后的修改时间等信息。而文件数据则是实际包含的数据。文件系统把一连串大小一致的数据块组织到一起称为页。当进程请求数据的时候,文件系统会首先确定数据在哪些扇区,然后把相关的扇区读入内存。

引入文件系统后,操作系统I/O的过程如下:

1) 确定请求的数据分布在哪些页
2) 在内核空间分配的足够的内存页,以便容纳的文件系统页
3) 在内存页和磁盘的文件系统页之间建立映射
4) 为每一个页产生一个页错误
5) 虚拟内存捕获页错误,执行系统调用,是发生错误的页重新有效
6) 一旦页面调入完成,文件系统对原始数据进行解析,取得需要的内容等信息

你可能感兴趣的:(java,nio)