文件系统Page Cache
当文件的数据被读入到内存里,会有一个 Page Cache与之对应,Page Cache就是文件的数据在内存中的表示。如果系统调用IO需要对这个文件就行read或write调用,只需要直接对对应的Page Cache进行相应的操作。只有Logical I/O ,没有Physical I/O,即没有磁盘的机械操作。如果是第一次读取,或Page Cache被替换掉时,内存中不存在对应的Page Cache,还是会有Physical I/O,但第二次再使用,可以使用已经在内存中的Page Cache。对Linux而言,会把读到的数据都会缓存起来,直到内存不够,才会进行Page Cache替换。文件系统Buffer Cache
磁盘块中的数据是缓存在一个叫Buffer Cache里,是磁盘块的数据在内存中的映射。和Page Cache类似,都是为了提高IO性能。Page Cache与Buffer Cache关系
磁盘上数据,在操作系统会缓存在这两个地方,不仅带了内存的开销的,也带了两份缓存数据保持一致性的开销。对其优化:Buffer Cache 和 Page Cache可以共用一份缓存,也就是说Buffer Cache缓存是通过Page Cache来实现,共用一份Page Cache,这样就解决了额外空间开销和维护数据一致性的开销。在内核版本2.4 以后,就使用了此优化。
优化之前:
优化之后:
文件系统预读
如果是顺序读以文件,应用程序调用read可能只读4KB数据,但文件系统会会从磁盘读取更多的数据,即从磁盘读取到内核的数据是大于4KB。这就是预读,当下次再读就可以直接返回了。 当然这个预读针对顺序读优化,如果是随机读,可能还会有额外的开销,因为多读取了无用的数据。mmap
通过mmap系统调用,把一个文件映射到进程虚拟址址空间上。磁盘上的文件在系统看来是一个内存数组了,这样应用程序访问文件就不需要系统IO调用,而是直接读取内存。调用mmap时,文件数据并不会马上读取内存,还是在实际需要时,才会按需调度进内核。
Zero Copy
在Linux内核2.4以后,提供更高效的sendfile系统调用,来实现Zero Copy。#include <sys/sendfile.h>
ssize_t sendfile(int out_fd, int in_fd, off_t *offset, size_t count);
普通的调用过程
read调用会产一次从磁盘上文件通过DMA Copy把数据读到内核中,然后把数据从内核通过CPU Copy复制到用户态。write调用会产生一个从用户态通过CPU Copy复制到内核态,然后内核在合适的时候,会把数据通过DMA Copy复制到磁盘上。所以普通的read, write会产生4次上下文切换,2次CPU Copy,2次DMA Copy。因为CPU是计算机的宝贵资源,所以CPU Copy CPU时间开销是很大的,而DMA Copy是异步的,事件通知机制,所以开销很小。
mmap调用过程
mmap调用会产一次从磁盘上文件通过DMA Copy技术把数据读到内核中,然后数据就可以和其它进程共享了。刷新数据调用会产生一个从用户态通过CPU Copy复制到内核态。所以普通的mmap会产生2次上下文切换,1次CPU Copy,2次DMA Copy。
sendfile调用过程
sendfile会产生2次DMA Copy,2次上下切换,没有CPU Copy。