Linux下磁盘的IO的各种机制

要说Linux下的IO过程,就要先说下Linux的地址空间问题,首先,Linux有一段虚拟内存,以32位x86系统为例,虚拟内存为2^32 即4G的内存空间,内核将这4G的空间分为两个部分,高位的1G字节(从虚地址0xC0000000到0xFFFFFFFF)供内核使用,称为“内核空间”。而较低的3G字节(从虚地址0x00000000到0xBFFFFFFF),供各个进程使用,称为“用户空间”。因为每个进程可以通过系统调用进入内核,因此,Linux内核空间由系统内的所有进程共享。于是,从具体进程的角度来看,每个进程可以拥有4G字节的虚拟地址空间(也叫虚拟内存)。(这里顺便提一下进程的上下文切换,当内核挂起一个进程,并储存该进程当时在内存中所反映出的状态或从内存中恢复下一个要执行的进程,恢复该进程原来的状态到寄存器,返回到其上次暂停的执行代码然后继续执行。这个过程就会引起进程的上下文切换,进程上下文切换智能发生在内核态)

在经典IO过程中,会有一块内核缓冲区和用户缓冲区,内核缓冲区在内核空间,在内存中,用于内核程序,做为读自或写往硬件的数据缓冲区,用户缓冲区在用户空间,在内存中,用于用户程序,做为读自或写往硬件的数据缓冲区。

在Linux下磁盘IO过程不是简单的一个读写,传统的IO方式,以read(),write()为例,其实Linux内部完成了很多次数据拷贝,当我们要read(),write()一个fd的时候,首先要将数据从磁盘中拷贝到内核空间的页缓存中,然后再将页缓存的数据拷贝到用户空间来,同理,write()一个fd的时候,也会将数据先写入内核空间的页缓存,然后再写入磁盘,如下图。

Linux下磁盘的IO的各种机制

还有一种是同步IO方式,本质上与传统IO方式没有什么不同,只是同步IO保证数据写入磁盘后才算IO过程完成,而传统IO将数据写入内核的高速缓冲区就算IO完成了


还有一种内存映射的IO方式,在Linux中,内存区域是可以跟一个普通的文件或设备文件的某一个部分关联起来的,若进程要访问内存页中某个字节的数据,操作系统就会将访问该内存区域的操作转换为相应的访问文件的某个字节的操作。Linux提供了mmap()来实现这种文件方式。与标准的访问文件的方式相比,内存映射方式可以减少标准访问文件方式中 read() 系统调用所带来的数据拷贝操作,即减少数据在用户地址空间和操作系统内核地址空间之间的拷贝操作。映射通常适用于较大范围,对于相同长度的数据来讲,映射所带来的开销远远低于 CPU 拷贝所带来的开销。当大量数据需要传输的时候,采用内存映射方式去访问文件会获得比较好的效率

Linux下磁盘的IO的各种机制

mmap()的作用是映射文件描述符和指定文件的(off_t off)区域至调用进程的(addr,addr *len)的内存区域,如下图所示:

Linux下磁盘的IO的各种机制


还有一种直接IO方式,凡是通过直接IO方式进行数据传输,数据均直接在用户地址空间的缓冲区和磁盘之间直接进行传输,完全不需要页缓存的支持。操作系统层提供的缓存往往会使应用程序在读写数据的时候获得更好的性能,但是对于某些特殊的应用程序,比如说数据库管理系统这类应用,他们更倾向于选择他们自己的缓存机制,因为数据库管理系统往往比操作系统更了解数据库中存放的数据,数据库管理系统可以提供一种更加有效的缓存机制来提高数据库中数据的存取性能。

                                       Linux下磁盘的IO的各种机制