思考
1.Linux读写文件会涉及几次上下文切换和数据拷贝?
2.用户态和内核态怎么理解?
3.page Cache属于哪一层缓存?
4.BufferedInputStream是减少哪一层耗时?
5.为什么需要这么多层缓存?
传统的IO拷贝过程
传统的IO拷贝过程,涉及用户态,内核态,磁盘。上图表示读写磁盘的过程图,数据需要从用户态拷贝到内核态再拷贝到磁盘,磁盘的数据也需要先到内核态再到用户态。这就需要了4次拷贝,从用户态切换到内核态,需要进行一次上下文切换,从内核态切换到用户态也需要进行一次上下文切换,如上图所示,需要4次上下文切换。
其它拷贝方式
如上图所示,application在用户态,page cache在内核态,mmap直接把Page Cache映射到了用户态的地址空间里了,所以mmap的方式从磁盘读文件是没有内核态到用户态的拷贝过程的。Direct IO则直接让用户态和块IO层对接,直接放弃Page Cache,从磁盘直接和用户态拷贝数据。
这两种方案,在写或第一次读的时候会比较快一点。至于第二次读呢,当然是拷贝到了最近的用户态会比较快一点。因为缓存的地方最近。
用户态和内核态怎么理解
cpu运行用户代码,就说cpu运行在用户态;cpu运行操作系统代码,cpu就运行在内核态;比如java的读磁盘IO,就要把文件从磁盘拷贝到操作系统内存(pagecache,这个时候cpu运行在内核态),然后再拷贝到jvm的内存(其实就是你程序里面用的字节数组接收),这个时候cpu是运行在用户态,所以叫做用户态内存。
BufferedInputStream是减少哪一层耗时
那这样看来,我们在调用java api操作io接口时,用到的缓存比如BufferedInputStream是为了减少哪一层呢,
其实减少的就是用户态到内核态的系统调用次数。
为什么需要这么多层缓存
其实这些用户态内存和内核态内存都处于虚拟空间中,都是对物理地址的映射,详细可以了解下虚拟内存,之所以这样分,我想主要是操作系统需要封装对磁盘的一些调用,这个调用是比较慢的,所以需要缓存;而我们的进程又是对操作系统的调用,所以数据缓存到离读取的地方越近越好。
参考链接: