1. 程式人生 > >Java NIO學習筆記---I/O與NIO概述

Java NIO學習筆記---I/O與NIO概述

文章目錄


轉載自 https://www.cnblogs.com/ysw-go/p/5971982.html?utm_source=itdadao&utm_medium=referral

一、什麼是IO

    I/O 或者輸入/輸出 , 指的是計算機與外部世界或者一個程式與計算機的其餘部分的之間的介面。它對於任何計算機系統都非常關鍵,因而所有 I/O 的主體實際上是內建在作業系統中的。單獨的程式一般是讓系統為它們完成大部分的工作。在 Java 程式設計中,直到最近一直使用 流 的方式完成 I/O。所有 I/O 都被視為單個的位元組的移動,通過一個稱為 Stream 的物件一次移動一個位元組。流 I/O 用於與外部世界接觸。它也在內部使用,用於將物件轉換為位元組,然後再轉換回物件。我們習慣上說到介面就是指I/O介面。

二、什麼是Java NIO

    nio 是 New I/O 的簡稱,屬於當時 jdk1.4 提供的新 api。如今 jdk 版本已經到 1.8 了,新 IO 這個稱謂有點不合適了,nio 還有一個更合適的叫法——非阻塞(non-blocking)IO。

三、I/O常見概念

3.1 DMA

    DMA(Direct Memory Access,直接記憶體存取) 是所有現代電腦的重要特色,在DMA控制器和記憶體之間傳輸資料的時候CPU是空閒的。在實現DMA傳輸時,是由DMA控制器直接掌管匯流排,因此,存在著一個匯流排控制權轉移問題。即DMA傳輸前,CPU要把匯流排控制權交給DMA控制器,而在結束DMA傳輸後,DMA控制器應立即把匯流排控制權再交回給CPU。一個完整的DMA傳輸過程必須經過DMA請求、DMA響應、DMA傳輸、DMA結束4個步驟。
    在dma傳輸資料的過程中,要求源實體地址和目標實體地址必須是連續的。但在有的計算機體系中,如IA,連續的儲存器地址在物理上不一定是連續的,則dma傳輸要分成多次完成。如果傳輸完一塊物理連續的資料後發起一次中斷,同時主機進行下一塊物理連續的傳輸,則這種方式即為block dma方式。scatter/gather方式則不同,它是用一個連結串列描述物理不連續的儲存器,然後把連結串列首地址告訴dma master。dma master傳輸完一塊物理連續的資料後,就不用再發中斷了,而是根據連結串列傳輸下一塊物理連續的資料,最後發起一次中斷。
很顯然scatter/gather方式比block dma方式效率高。

3.2 核心空間和使用者空間

    使用者空間是常規程序所在區域。JVM就是常規程序,駐守於使用者空間。使用者空間是非特權區域:比如,在該區域執行的程式碼就不能直接訪問硬體裝置。核心空間是作業系統所在區域。核心程式碼有特別的權力:它能與裝置控制器通訊,控制著使用者區域程序的執行狀態,等等。最重要的是,所有I/O都直接或間接通過核空間。
    當程序請求I/O操作的時候,它執行一個系統呼叫將控制權移交給核心。當核心以這種方式被呼叫,它隨即採取任何必要步驟,找到程序所需資料,並把資料傳送到使用者空間內的指定緩衝區。核心試圖對資料進行快取記憶體或預讀取,因此程序所需資料可能已經在核心空間裡了。如果是這樣,該資料只需簡單地拷貝出來即可。如果資料不在核心空間,則程序被掛起,核心著手把資料讀進記憶體。
    為什麼不直接讓磁碟控制器把資料送到使用者空間的緩衝區呢?這樣做有幾個問題。首先,硬體通常不能直接訪問使用者空間 (硬體裝置通常不能直接使用虛擬記憶體地址) 。其次,像磁碟這樣基於塊儲存的硬體裝置操作的是固定大小的資料塊,而使用者程序請求的可能是任意大小的或非對齊的資料塊。在資料往來於使用者空間與儲存裝置的過程中,核心負責資料的分解、再組合工作,因此充當著中間人的角色。

3.3 虛擬記憶體

    所有現代作業系統都使用虛擬記憶體。虛擬記憶體意為使用虛假(或虛擬)地址取代物理(硬體RAM)記憶體地址。這樣做好處頗多,總結起來可分為兩大類:
    一個以上的虛擬地址可指向同一個實體記憶體地址。
    虛擬記憶體空間可大於實際可用的硬體記憶體。
    裝置控制器不能通過DMA直接儲存到使用者空間,但通過利用上面提到的第一項,則可以達到相同效果。把核心空間地址與使用者空間的虛擬地址對映到同一個實體地址,這樣,DMA硬體(只能訪問實體記憶體地址)就可以填充對核心與使用者空間程序同時可見的緩衝區。但前提條件是,核心與使用者緩衝區必須使用相同的頁對齊,緩衝區的大小還必須是磁碟控制器塊大小(通常為512 位元組磁碟扇區)的倍數。作業系統把記憶體地址空間劃分為頁,即固定大小的位元組組。記憶體頁的大小總是磁碟塊大小的倍數,通常為2次冪(這樣可簡化定址操作)。典型的記憶體頁為1,024、2,048和4,096位元組。

3.4 現代作業系統的分頁技術

    現代CPU包含一個稱為記憶體管理單元(MMU)的子系統,邏輯上位於CPU與實體記憶體之間。該裝置包含虛擬地址向實體記憶體地址轉換時所需對映資訊。當CPU引用某記憶體地址時,MMU負責確定該地址所在頁(往往通過對地址值進行移位或遮蔽位操作實現),並將虛擬頁號轉換為物理頁號(這一步由硬體完成,速度極快)。如果當前不存在與該虛擬頁形成有效對映的實體記憶體頁,MMU會向CPU提交一個頁錯誤。頁錯誤隨即產生一個系統呼叫,把控制權移交給核心,附帶導致錯誤的虛擬地址資訊,然後核心採取步驟驗證頁的有效性。核心會安排頁面調入操作,把缺失的頁內容讀回實體記憶體。這往往導致別的頁被移出實體記憶體,好給新來的頁讓地方。在這種情況下,如果待移出的頁已經被碰過了(自建立或上次頁面調入以來,內容已發生改變),還必須首先執行頁面調出,把頁內容拷貝到磁碟上的分頁區。
    如果所要求的地址不是有效的虛擬記憶體地址(不屬於正在執行的程序的任何一個記憶體段),則該頁不能通過驗證,段錯誤隨即產生。於是,控制權轉交給核心的另一部分,通常導致的結果就是程序被強令關閉。一旦出錯的頁通過了驗證,MMU隨即更新,建立新的虛擬到物理的對映(如有必要,中斷被移出頁的對映),使用者程序得以繼續。造成頁錯誤的使用者程序對此不會有絲毫察覺,一切都在不知不覺中進行。

3.5 面向塊(檔案)的I/O和流I/O

    檔案I/O屬檔案系統範疇,檔案系統與磁碟迥然不同。磁碟把資料存在扇區上,通常一個扇區512 位元組。磁碟屬硬體裝置,對何謂檔案一無所知,它只是提供了一系列資料存取視窗。在這點上,磁碟扇區與記憶體頁頗有相似之處:都是統一大小,都可作為大的陣列被訪問。
    檔案系統是更高層次的抽象,是安排、解釋磁碟(或其他隨機存取塊裝置)資料的一種獨特方式。您所寫程式碼幾乎無一例外地要與檔案系統打交道,而不是直接與磁碟打交道。是檔案系統定義了檔名、路徑、檔案、檔案屬性等抽象概念。檔案系統把一連串大小一致的資料塊組織到一起。有些塊儲存元資訊,如空閒塊、目錄、索引等的對映,有些包含檔案資料。單個檔案的元資訊描述了哪些塊包含檔案資料、資料在哪裡結束、最後一次更新是什麼時候,等等。
    當用戶程序請求讀取檔案資料時,檔案系統需要確定資料具體在磁碟什麼位置,然後著手把相關磁碟扇區讀進記憶體。老式的作業系統往往直接向磁碟驅動器釋出命令,要求其讀取所需磁碟扇區。而採用分頁技術的現代作業系統則利用請求頁面排程取得所需資料。
    採用分頁技術的作業系統執行I/O的全過程可總結為以下幾步:

  1. 確定請求的資料分佈在檔案系統的哪些頁(磁碟扇區組)。磁碟上的檔案內容和元資料可能跨越多個檔案系統頁,而且這些頁可能也不連續。
  2. 在核心空間分配足夠數量的記憶體頁,以容納得到確定的檔案系統頁。
  3. 在記憶體頁與磁碟上的檔案系統頁之間建立對映。
  4. 為每一個記憶體頁產生頁錯誤。
  5. 虛擬記憶體系統俘獲頁錯誤,安排頁面調入,從磁碟上讀取頁內容,使頁有效。
  6. 一旦頁面調入操作完成,檔案系統即對原始資料進行解析,取得所需檔案內容或屬性資訊。

    大多數作業系統假設程序會繼續讀取檔案剩餘部分,因而會預讀額外的檔案系統頁。如果記憶體爭用情況不嚴重,這些檔案系統頁可能在相當長的時間內繼續有效。這樣的話,當稍後該檔案又被相同或不同的程序再次開啟,可能根本無需訪問磁碟。這種情況您可能也碰到過:當重複執行類似的操作,如在幾個檔案中進行字串檢索,第二遍執行得似乎快多了。
    類似的步驟在寫檔案資料時也會採用。這時,檔案內容的改變(通過write( ))將導致檔案系統頁變髒,隨後通過頁面調出,與磁碟上的檔案內容保持同步。檔案的建立方式是,先把檔案對映到空閒檔案系統頁,在隨後的寫操作中,再將檔案系統頁重新整理到磁碟。
    並非所有I/O都是面向塊的,也有流I/O,其原理模仿了通道。I/O位元組流必須順序存取,常見的例子有TTY(控制檯)裝置、印表機埠和網路連線。
    流的傳輸一般(也不必然如此)比塊裝置慢,經常用於間歇性輸入。多數作業系統允許把流置於非阻塞模式,這樣,程序可以檢視流上是否有輸入,即便當時沒有也不影響它幹別的。這樣一種能力使得程序可以在有輸入的時候進行處理,輸入流閒置的時候執行其他功能。比非阻塞模式再進一步,就是就緒性選擇。就緒性選擇與非阻塞模式類似(常常就是建立在非阻塞模式之上),但是把檢視流是否就緒的任務交給了作業系統。作業系統受命檢視一系列流,並提醒程序哪些流已經就緒。這樣,僅僅憑藉作業系統返回的就緒資訊,程序就可以使用相同程式碼和單一執行緒,實現多活動流的多路傳輸。這一技術廣泛用於網路伺服器領域,用來處理數量龐大的網路連線。就緒性選擇在大容量縮放方面是必不可少的。

3.6 記憶體對映檔案

    記憶體對映I/O使用檔案系統建立從使用者空間直到可用檔案系統頁的虛擬記憶體對映。這樣做有幾個好處:

  1. 使用者程序把檔案資料當作記憶體,所以無需釋出read( )或write( )系統呼叫。
  2. 當用戶程序碰觸到對映記憶體空間,頁錯誤會自動產生,從而將檔案資料從磁碟讀進記憶體。如果使用者修改了對映記憶體空間,相關頁會自動標記為髒,隨後重新整理到磁碟,檔案得到更新。
  3. 作業系統的虛擬記憶體子系統會對頁進行智慧快取記憶體,自動根據系統負載進行記憶體管理。
  4. 資料總是按頁對齊的,無需執行緩衝區拷貝。
  5. 大型檔案使用對映,無需耗費大量記憶體,即可進行資料拷貝。

3.7 檔案鎖定

    檔案鎖定機制允許一個程序阻止其他程序存取某檔案,或限制其存取方式。通常的用途是控制共享資訊的更新方式,或用於事務隔離。在控制多個實體並行訪問共同資源方面,檔案鎖定是必不可少的。資料庫等複雜應用嚴重信賴於檔案鎖定。
 &3160;  “檔案鎖定”從字面上看有鎖定整個檔案的意思(通常的確是那樣),但鎖定往往可以發生在更為細微的層面,鎖定區域往往可以細緻到單個位元組。鎖定與特定檔案相關,開始於檔案的某個特定位元組地址,包含特定數量的連續位元組。這對於協調多個程序互不影響地訪問檔案不同區域,是至關重要的。
 &3160;  檔案鎖定有兩種方式:共享的和獨佔的。多個共享鎖可同時對同一檔案區域發生作用;獨佔鎖則不同,它要求相關區域不能有其他鎖定在起作用。

四、為什麼使用NIO

    I/O的終極目標是效率,而效率離不開底層作業系統和檔案系統的特性支援。這些特性包括:檔案鎖定、非阻塞I/O、就緒性選擇、和記憶體對映。當今作業系統大都支援這些特性,而Java傳統I/O機制並沒有模擬這些通用的I/O服務。NIO 的建立目的是為了讓 Java 程式設計師可以實現高速 I/O 而無需編寫自定義的本機程式碼。NIO 將最耗時的 I/O 操作(即填充和提取緩衝區)轉移回作業系統,因而可以極大地提高速度。通常一次緩衝區操作是這樣的:某個程序需要進行I/O操作,它執行了一次讀(read)或者寫(write)的系統呼叫,向底層作業系統發出了請求,作業系統會按要求把資料緩衝區填滿或者排幹。
    對於檔案I/O,整合的 I/O提供了對於NIO特性的支援。 企業級應用軟體中涉及I/O的部分多半是讀寫檔案的功能性需求,很少有在併發上的要求,那麼JavaIO包已經很勝任了。
    對於網路I/O,傳統的阻塞式I/O,一個執行緒對應一個連線,採用執行緒池的模式在大部分場景下簡單高效。當連線數非常多時,並且資料的移動非常頻繁,NIO無疑是更好的選擇。

五、IO VS NIO

5.1 檔案流與檔案塊的比較

    原來的 I/O 庫(在 java.io.*中) 與 NIO 最重要的區別是資料打包和傳輸的方式。原來的 I/O 以流的方式處理資料,經常為了處理個別字節或字元,就要執行好幾個物件層的方法呼叫。而 NIO 以塊的方式處理資料。面向流 的 I/O 系統一次一個位元組地處理資料。一個輸入流產生一個位元組的資料,一個輸出流消費一個位元組的資料。為流式資料建立過濾器非常容易。連結幾個過濾器,以便每個過濾器只負責單個複雜處理機制的一部分,這樣也是相對簡單的。不利的一面是,面向流的 I/O 通常相當慢。一個 面向塊 的 I/O 系統以塊的形式處理資料。每一個操作都在一步中產生或者消費一個數據塊。按塊處理資料比按(流式的)位元組處理資料要快得多。但是面向塊的 I/O 缺少一些面向流的 I/O 所具有的優雅性和簡單性。

5.2 整合的 檔案I/O

    在 JDK 1.4 中原來的 I/O 包和 NIO 已經很好地集成了。 java.io.* 已經以 NIO 為基礎重新實現了,所以現在它可以利用 NIO 的一些特性。例如, java.io.* 包中的一些類包含以塊的形式讀寫資料的方法,這使得即使在更面向流的系統中,處理速度也會更快。也可以用 NIO 庫實現標準 I/O 功能。例如,可以容易地使用塊 I/O 一次一個位元組地移動資料。NIO 還提供了原 I/O 包中所沒有的許多好處。
引用連結:(有些連結需要FQ),感謝原創作者的知識分享
1.http://blog.csdn.net/tsyj810883979/article/details/6876594#comments
2.http://www.iteye.com/magazines/132-Java-NIO
3.http://ifeve.com/overview/
4.http://www.ibm.com/developerworks/cn/education/java/j-nio/j-nio.html
5.http://www.myexception.cn/internet/1218142.html
6.http://www.jb51.net/article/50621.htm
7.http://www.yangyong.me/java-nio入門與詳解/
8.Java NIO中文版