1.緩沖區 緩沖區是所有IO的基礎,”輸入/輸出”就是將數據移進或移除緩沖區。進程IO操作的執行也是向操作系統發送請求,讓它要么將緩沖區的數據排干(寫),要么將緩沖區的填滿數據(讀)。 圖 1-1 簡單描述了數據從外部磁盤向運行中的進程的內存區域移動的過程。進程使用 read()系統調用,要求其緩沖區被填滿。內核隨即向磁盤控制硬件發出命令,要求其從磁盤讀取數據。磁盤控制器把數據直接寫入內核內存緩沖區,這一步通過 DMA 完成,無需主CPU協助。一旦磁盤控制器把緩沖區裝滿,內核即把數據從內核空間的臨時緩沖區拷貝到進程執行read()調用時指定的緩沖區。 2.用戶空間和系統空間
用戶空間是常規進程所在區域。JVM 就是常規進程,駐守于用戶空間。用戶空間是非特權區域:比如,在該區域執行的代碼就不能直接訪問硬件設備。 內核空間是操作系統所在區域。內核代碼有特別的權力:它能與設備控制器通訊,控制著用戶區域進程的運行狀態,等等。最重要的是,所有I/O都直接或間接通過內核空間。 當進程請求I/O操作的時候,它執行一個系統調用(有時稱為陷阱)將控制權移交給內核。C/C++程序員所熟知的底層函數open()、read()、write()和close()要做的無非就是建立和執行適當的系統調用。當內核以這種方式被調用,它隨即采取任何必要步驟,找到進程所需數據,并把數據傳送到用戶空間內的指定緩沖區。內核試圖對數據進行高速緩存或預讀取,因此進程所需數據可能已經在內核空間里了。如果是這樣,該數據只需簡單地拷貝出來即可。如果數據不在內核空間,則進程被掛起,內核著手把數據讀進內存。
您可能會覺得,把數據從內核空間拷貝到用戶空間似乎有些多余。為什么不直接讓磁盤控制器把數據送到用戶空間的緩沖區呢? 這樣做有幾個問題。 首先,硬件通常不能直接訪問用戶空間 其次,像磁盤這樣基于塊存儲的硬件設備操作的是固定大小的數據塊,而用戶進程請求的可能是任意大小的或非對齊的數據塊。在數據往來于用戶空間與存儲設備的過程中,內核負責數據的分解、再組合工作,因此充當著中間人的角色。 3.虛擬內存 虛擬內存意為使用虛假(或虛擬)地址取代物理(硬件RAM)內存地址 (1)一個以上的虛擬地址可指向同一個物理內存地址. (2)虛擬內存空間可大于實際可用的硬件內存. 設備控制器不能通過DMA直接存儲到用戶空間,但通過利用上面提到的第一項,則可以達到相同效果。把內核空間地址與用戶空間的虛擬地址映射到同一個物理地址,這樣,DMA 硬件(只能訪問物理內存地址)就可以填充對內核與用戶空間進程同時可見的緩沖區(見圖1-3)。 4.內存頁面調度 為了支持虛擬內存的第二個特性(尋址空間大于物理內存),就必須進行虛擬內存分頁(經常稱為交換,雖然真正的交換是在進程層面完成,而非頁層面)。依照該方案,虛擬內存空間的頁面能夠繼續存在于外部磁盤存儲,這樣就為物理內存中的其他虛擬頁面騰出了空間。從本質上說,物理內存充當了分頁區的高速緩存;而所謂分頁區,即從物理內存置換出來,轉而存儲于磁盤上的內存頁面。 現代CPU包含一個稱為內存管理單元(MMU)的子系統,邏輯上位于CPU與物理內存之間。該設備包含虛擬地址向物理內存地址轉換時所需映射信息。當CPU引用某內存地址時,MMU負責確定該地址所在頁(往往通過對地址值進行移位或屏蔽位操作實現),并將虛擬頁號轉換為物理頁號(這一步由硬件完成,速度極快)。如果當前不存在與該虛擬頁形成有效映射的物理內存頁,MMU會向CPU 提交一個頁錯誤。 5.文件IO 文件系統是更高層次的抽象,是安排、解釋磁盤(或其他隨機存取塊設備)數據的一種獨特方式。您所寫代碼幾乎無一例外地要與文件系統打交道,而不是直接與磁盤打交道。是文件系統定義了文件名、路徑、文件、文件屬性等抽象概念。 所有I/O都是通過請求頁面調度完成的。頁面調度是非常底層的操作,僅發生于磁盤扇區與內存頁之間的直接傳輸。而文件 I/O 則可以任意大小、任意定位。那么,底層的頁面調度是如何轉換為文件 I/O 的? 文件系統把一連串大小一致的數據塊組織到一起。有些塊存儲元信息,如空閑塊、目錄、索引等的映射,有些包含文件數據。單個文件的元信息描述了哪些塊包含文件數據、數據在哪里結束、最后一次更新是什么時候,等等。 當用戶進程請求讀取文件數據時,文件系統需要確定數據具體在磁盤什么位置,然后著手把相關磁盤扇區讀進內存。老式的操作系統往往直接向磁盤驅動器發布命令,要求其讀取所需磁盤扇區。而采用分頁技術的現代操作系統則利用請求頁面調度取得所需數據。 采用分頁技術的操作系統執行 I/O 的全過程可總結為以下幾步: 1、確定請求的數據分布在文件系統的哪些頁(磁盤扇區組)。磁盤上的文件內容和元數據可能跨越多個文件系統頁,而且這些頁可能也不連續。 2、在內核空間分配足夠數量的內存頁,以容納得到確定的文件系統頁。 3、在內存頁與磁盤上的文件系統頁之間建立映射。 4、為每一個內存頁產生頁錯誤。 5、虛擬內存系統俘獲頁錯誤,安排頁面調入,從磁盤上讀取頁內容,使頁有效。 6、一旦頁面調入操作完成,文件系統即對原始數據進行解析,取得所需文件內容或屬性信息。 需要注意的是,這些文件系統數據也會同其他內存頁一樣得到高速緩存。對于隨后發生的 I/O請求,文件數據的部分或全部可能仍舊位于物理內存當中,無需再從磁盤讀取即可重復使用。 6.映射內存文件
內存映射I/O使用文件系統建立從用戶空間直到可用文件系統頁的虛擬內存映射。這樣做有幾 個好處: 1、用戶進程把文件數據當作內存,所以無需發布 read( )或 write( )系統調用。 2、當用戶進程碰觸到映射內存空間,頁錯誤會自動產生,從而將文件數據從磁盤讀進內存。如果用戶修改了映射內存空間,相關頁會自動標記為臟,隨后刷新到磁盤,文件得到更新。 3、操作系統的虛擬內存子系統會對頁進行智能高速緩存,自動根據系統負載進行內存管理。 4、數據總是按頁對齊的,無需執行緩沖區拷貝。 5、大型文件使用映射,無需耗費大量內存,即可進行數據拷貝。 虛擬內存和磁盤 I/O 是緊密關聯的,從很多方面看來,它們只是同一件事物的兩面。在處理大量數據時,尤其要記得這一點。如果數據緩沖區是按頁對齊的,且大小是內建頁大小的倍數,那么,對大多數操作系統而言,其處理效率會大幅提升。 7.文件鎖定
文件鎖定有兩種方式:共享的和獨占的。多個共享鎖可同時對同一文件區域發生作用;獨占鎖則不同,它要求相關區域不能有其他鎖定在起作用。
參考:《java NIO》
新聞熱點
疑難解答