Java NIO系列1:從作業系統的角度剖析I/O

rhwayfunn發表於2016-04-18

認識IO的本質

一、IO對效能的影響

首先來理解下IO對程式效能的影響:

對吞吐率的影響

從上面的表中可以得出的結論是:處理時間與IO時間對吞吐率的影響:把單位處理時間減半,僅能提高吞吐率2.2%。而僅僅縮短I/O延遲10%,就可使吞吐率增加9.7%;把I/O時間減半,吞吐率幾乎翻番

二、理解BIO的侷限性

BIO,也稱為阻塞IO,是在jdk1.4之前使用的IO模型,BIO的侷限可以從下面的敘述中理解:

現在大多數基於Java的應用在處理資料上的不足在於JVM對IO處理的效率。作業系統往往傳送給緩衝區的資料是塊資料,而JVM的BIO類則把塊資料切分為一個一個位元組(或者幾行文字資料)進行處理,而一次資料的拷貝需要往返幾個來回。所以可見傳統的BIO類在處理資料的低效。當然,BIO類也可以傳送大量的資料,那就是用RandomAccessFile類。而該類提高效率的關鍵是使用類似於作業系統的read與write系統呼叫。

這就是說,只要直接使用Java本地介面編寫程式,那麼IO的效率是不是就能提高了呢?固然,但是直接操作本地作業系統的特性會使得程式繫結於某一類的作業系統,程式無法移植。為了保持Java跨平臺的特性,Sun公司推出了java.nio包。具體其實Channel類和Selector類。

IO的作業系統解釋

一、緩衝區操作

IO的基礎就是緩衝區,本質上將,IO也就是輸入/輸出,實際上是對資料在緩衝區的移入和移出。

下面這張圖描繪了IO的處理處理過程:

IO呼叫

當程式執行IO請求時,(程式屬於使用者空間)程式會執行一次系統呼叫(也稱為陷進)把控制權交給核心。核心接收到請求後,如果資料不在告訴快取中,會去尋找程式需要的資料並把資料載入到

程式指定的使用者空間的緩衝區中;如果程式請求的資料已經在告訴快取中,那麼只需要把快取記憶體的資料拷貝到緩衝區即可。

這個過程展示了核心作為中間角色作用,核心直接與硬體裝置打交道,使用者空間不能直接與硬體裝置。這點的原因有兩個:一是使用者空間的地址都是虛擬地址(至於為什麼是虛擬地址則可能需要閱讀作業系統的資料了),虛擬地址必須經過轉換才能訪問硬體裝置,這個過程是由MMU(記憶體管理單元)來完成的;二是為了安全

二、虛擬記憶體

現代作業系統都使用虛擬記憶體,所謂虛擬記憶體就是使用虛假的記憶體地址取代實體地址(裝置地址)。

這樣做的好處有兩點:一是一個以上的虛擬記憶體地址可以指向同一個實體地址;二是虛擬記憶體空間可大於實體地址空間。

由於作業系統的虛擬記憶體使用能夠頁式管理方案(記憶體地址一頁一頁存放),所以採用虛擬記憶體後,程式對裝置的操作就大大簡化了,通過對記憶體空間的對映,使用者空間與記憶體空間的緩衝區可以指向同一段實體記憶體空間,這樣程式在請求資料的時候就不用在使用者空間和核心空間來回拷貝資料了。

為什麼虛擬記憶體空間可以大於實體地址空間,主要是因為程式暫時不用的頁面(虛擬記憶體採用記憶體分頁的方式)儲存在外部磁碟,將需要的頁面調入記憶體,原來不用的頁面再被置換出去,這樣就實現了虛擬記憶體地址空間大於實體地址空間。

虛擬記憶體採用記憶體分頁後,記憶體地址就以頁為單位進行管理。回到之前程式請求資料(也就是I/O啦)的過程,MMU會首先找到虛擬地址對應的頁,然後根據虛擬頁號對映到物理的記憶體頁號(這個過程由硬體完成,速度很快)。

如果當前不存在物理頁號與該虛擬頁號的對映,那麼會產生一個頁錯誤。發生頁錯誤後,程式會執行一次系統呼叫,從使用者態陷入核心態,附帶出錯的虛擬地址資訊,把缺失的頁重新調入實體記憶體。因為實體記憶體調入的頁面數往往是固定的,那麼調入一個新的頁面勢必就會導致一箇舊頁面被置換出實體記憶體,這個被置換出去的頁面如果是髒的,那麼需要首先執行頁面調出,將頁面的記憶體輸出到磁碟的分頁區。一旦出錯的頁重新調入記憶體,MMU也會更新新的虛擬地址到實體地址的對映。

三、檔案IO

檔案IO不同於程式請求資料這一模型,因為檔案IO需要與檔案系統打交道,而本質上IO都是底層頁面的排程的操作,也就是磁碟扇區與記憶體頁面之間的互動。現在IO需要通過檔案系統,那麼檔案系統是如何完成這個過程的轉換呢?

瞭解作業系統的都知道,檔案系統實際上的檔案的高階抽象,把檔案分為後設資料和資料,每個檔案都有後設資料,後設資料描述了哪些檔案塊包含該資料,資料在哪裡開始,哪裡結束以及最後的修改時間等資訊。而檔案資料則是實際包含的資料。檔案系統把一連串大小一致的資料塊組織到一起稱為頁。當程式請求資料的時候,檔案系統會首先確定資料在哪些扇區,然後把相關的扇區讀入記憶體。

引入檔案系統後,作業系統I/O的過程如下:

1) 確定請求的資料分佈在哪些頁
2) 在核心空間分配的足夠的記憶體頁,以便容納的檔案系統頁
3) 在記憶體頁和磁碟的檔案系統頁之間建立對映
4) 為每一個頁產生一個頁錯誤
5) 虛擬記憶體捕獲頁錯誤,執行系統呼叫,是發生錯誤的頁重新有效
6) 一旦頁面調入完成,檔案系統對原始資料進行解析,取得需要的內容等資訊

相關文章