文章想进可能的详述磁盘IO的机制,所以java提供的IO类库太多,所以就一概不提了。
凡是涉及到IO就是数据的读取和写入的问题,而IO问题是大多程序都避免不了的问题。因为IO速度远慢于CPU的执行速度,所以IO问题很容易成为程序运行的瓶颈。正因为如此,java提供了几种不同的IO机制,并于1.4开始引进NIO用以提升IO速度。
所谓IO,无非就是内核空间和用户空间的数据交换。当程序发起read()命令是,把数据从内核缓冲区搬到用户缓冲区(也就是你自己写的byte数组),当程序发起write()操作时把数据放到内核缓冲区。这看起来很简单,底层实现其来或者实现各种优化确实很麻烦。
用户态和内核态的切换很消耗性能,一旦涉及的磁盘操作,还会有硬件参与数据的拷贝传输。
- 缓冲IO
我们都知道访问磁盘的代价是很大的,所以为了减少的对磁盘的访问,在我们第一次读取数据的时候,我们会先从磁盘中读取更多的数据放到内核缓冲中。
当读取数据是,如果这时候内核缓冲中已经有数据,就直接返回。否则,再从磁盘中读取数据放到内核缓冲,并从内核缓存拷贝到用户缓存中。
内核缓存存在的意义是,每次都从磁盘读取固定大小的数据预备着应用程序的读取。
而对于写操作来说,把数据放到内核缓存中,就算是结束了。至于什么时候写到磁盘就是由操作系统决定了。
缓存I/O的优点:1)在一定程度上分离了内核空间和用户空间,保护系统本身的运行安全;2)可以减少读盘的次数,从而提高性能。
缓存I/O的缺点:数据在传输过程中需要在应用程序地址空间和缓存之间进行多次数据拷贝操作,这些数据拷贝操作所带来的CPU以及内存开销是非常大的。
- 直接IO方式
所谓直接IO就是应用程序直接访问磁盘数据,而不经过操作系统内核的数据缓冲。这样做的目的是减少数据的拷贝。标准的IO方式,会把数据从磁盘拷贝到内核缓冲区,再拷贝到用户缓冲区。而直接访问的方式就是减少了中间内核缓冲区的数据拷贝。
这种访问文件的方式在数据库管理系统中比较常见。它们更倾向于选择它们自己的缓存机制,因为数据库管理系统往往比操作系统更了解数据库中存放的数据,数据库管理系统可以提供一种更加有效的缓存机制来提高数据库中数据的存取性能。
直接IO的缺点:如果访问的数据不在应用程序缓存中,那么每次数据都会直接从磁盘加载,这种直接加载会非常缓存。通常直接IO与异步IO结合使用,会得到比较好的性能。(异步IO:当访问数据的线程发出请求之后,线程会接着去处理其他事,而不是阻塞等待)
- 内存映射方式
内存映射是指将硬盘上文件的位置与进程逻辑地址空间中一块大小相同的区域一一对应
操作系统将内存中的某一块数据,与磁盘中的文件关联起来,当要访问内存中的一段数据是,就会转换为访问磁盘中文件的某一段数据。
这种方式同样减少了数据从内核缓存到用户缓存的数据拷,因为这两个空间的地址是共享的。。当大量数据要访问时,这种方式提供了较好的性能。
使用内存映射文件处理存储于磁盘上的文件时,将不必再对文件执行I/O操作,这意味着在对文件进行处理时将不必再为文件申请并分配缓存,所有的文件缓存操作均由系统直接管理,由于取消了将文件数据加载到内存、数据从内存到文件的回写以及释放内存块等步骤,使得内存映射文件在处理大数据量的文件时能起到相当重要的作用。
网友评论