天天3分鐘操做系統修煉祕籍(13):兩個緩衝空間Kernel Buffer和IO Buffer

兩個緩衝空間:kernel buffer和io buffer

先看一張圖,稍後將圍繞這張圖展開描述。圖中的fd table、open file table以及兩個inode table均可以不用理解,只須要知道它們體現出來的文件描述符和磁盤文件之間的對應關係:文件描述符fd(例如圖中的fd=3)是對應磁盤上文件的。node

在Linux下,咱們常常會在IO操做時不可避免的涉及到文件描述符,由於Linux下的全部IO操做都是經過文件描述符來完成的。可是,文件描述符是一個很是底層的概念,經過它操做的數據,都是二進制數據,因此經過文件描述符完成IO的模式一般也稱爲裸IO(Raw IO)。並且,直接經過底層的文件描述符進行編程會比較麻煩,由於是二進制數據,它缺乏不少功能,好比沒法指定編碼,沒法指定換行符(換行符有多種:\n、\n\r、\r)等等。注意fd是用戶空間的,它僅僅是一個數值而已,並非想象中感受比較底層就在內核空間。數據庫

因此,現代高級語言(好比C、Python、Java、Golang)都提供了比文件描述符更高一層次的標準IO庫,好比C的標準IO庫是stdio,Python的標準IO庫是IO模塊,等等。使用這些標準IO庫中的函數進行IO操做時,都會使用比文件描述符更高一層次的對象,例如C中稱爲IO流(io stream),其它面向對象的語言中通常稱爲IO對象,爲了方便說明,這裏統稱爲IO對象。上圖中的F就是文件對象。編程

標準IO庫能夠看做是文件描述符的更高層次的封裝,提供了比文件描述符操做IO更多的功能。例如,能夠在IO對象上指定編碼、指定換行符,此外還在用戶空間提供了一個標準IO庫的緩衝空間,一般可稱爲stdio bufferIO buffer,而這些功能在文件描述符上都是沒有的。另外,標準IO庫既然是高層封裝,固然也會提供用戶不使用這些功能(好比不使用IO Buffer),而是直接使用文件描述符,那麼這時候的文件對象就至關因而文件描述符了,這時候的IO操做模式也就是裸IO模式。函數

全部從硬件讀取或寫入到硬件的數據,默認都會通過操做系統維護的這個Kernel Buffer。正如上圖中描述的是讀數據過程。性能

例如,cat進程想要讀取a.log文件,cat進程是用戶空間進程,它自身沒有權限打開文件以及讀文件數據,它只能經過系統調用的方式陷入內核,請求操做系統幫助讀取數據,操做系統讀取數據後會將數據放入到page cache(剛纔已說明,對於普通文件維護的Kernel buffer稱爲page cache或buffer cache)。而後還要將內核空間page cache中的數據拷貝到用戶空間的IO Buffer緩衝空間(由於cat程序的源代碼中使用了標準IO庫stdio),而後cat進程從本身的IO Buffer中讀取數據。這就是整個讀數據的過程。優化

須要注意的是,雖然這兩段緩衝空間都在內存中,但仍然有拷貝操做,由於內核的內存空間和用戶進程的虛擬內存空間是隔離的,用戶空間進程沒有權限訪問到內核空間的內存,可是內核具備最高權限,容許訪問任何內存地址。換句話說,在將Kernel Buffer的數據拷貝到IO Buffer空間的過程當中,須要陷入到內核,OS須要掌控CPU。編碼

此外,Linux也提供了所謂的直接IO模式,只需使用一個稱爲O_DIRECT的標記便可,這時會繞過Kernel Buffer,直接將硬件數據拷貝到用戶空間。雖然看上去直接IO少了一個層次的參與感受性能會更優秀,但實際上並不是如此,操做系統爲內核緩衝空間作了很是多的優化,使得並不會所以而下降性能。最典型且常見的一個優化是預讀功能,它表示在讀數據時,會比所請求要讀取的數據量多讀一點放入到Kernel Buffer,這樣在下次讀取接下來的一段數據時能夠直接從Kernel Buffer中取數據,而無需再和硬件IO交互。因此,使用直接IO模式的場景是很是少的,通常只會在自帶了完整緩衝模型的大型軟件(好比數據庫系統)上可能會使用直接IO模式。操作系統

上面所描述的都是讀操做,關於寫操做,這裏再也不多花篇幅去描述,總體過程和讀是相似的,都會通過IO Buffer和Kernel Buffer,只是其中一些細節有所不一樣,若是感興趣,能夠閱讀《Linux/Unix系統編程手冊》的第13章。對象

相關文章
相關標籤/搜索