1. Buffer IO
普通的IO读写,一般会经过 用户态内存--> PageCache--> FileSystem--> Block IO。
代码层面,读写的流程:
- malloc: 申请用户态内存;
- fwrite: 写入用户态内存;
flush: 将用户态内存flush到内核态的PageCache;
- 内核态的PageCache会被异步的写入disk;
- 可通过sync()系统调用,同步的将PageCache写入disk;
{
char *buf = malloc(MAX_BUF_SIZE); //申请app内的buffer
strncpy(buf, src, , MAX_BUF_SIZE);
fwrite(buf, MAX_BUF_SIZE, 1, fp); //写入app的buffer
fflush(fp); //将app的buffer刷入kernel的page cache
}
2. Direct IO
Direct IO不经过内核的PageCache,多用于数据库的场景,比如MySQL。
这类上层的应用通常需要自己管理I/O的读写缓存,它比内核更了解哪些数据该换入换出,在读写流程上一般会经过FileSystem向设备IO请求读写。
3. mmap
mmap将PageCache映射到用户的虚拟内存地址,用户代码可以直接以内存访问的方式,通过Page fault与内核交互。
mmap的特点:
- 读文件时,减少了一次PageCache--->用户态内存的COPY;
- 若文件的更新操作较多,会触发大量的脏页回写到disk,引发随机I/O,所以在随机写的场景下,mmap的效率不一定比Buffer IO高;
- mmap对变长的文件不适合:对变长的文件,需要频繁的申请或回收内存,引发Page Fault;
- mmap对小文件不适合:因为内存页最小是4KB,若整个映射到PageCache,会造成内存浪费;
参考:
1.https://www.zhihu.com/question/265246208
2.https://www.jianshu.com/p/755338d11865