天天看點

Java檔案讀寫原理和虛拟記憶體

  後面打算系統性的介紹下NIO和Netty的内容,因為這塊内容也是每個程式員必須要掌握的内容,而在介紹NIO之前我們需要先了解下一些前置的知識

1.核心空間和使用者空間

  這兩個概念對于初次接觸的小夥伴來說并不是很好了解,舉個簡單例子如下圖:

Java檔案讀寫原理和虛拟記憶體

  上圖中的儲戶是沒法直接從金庫中存錢擷取取錢的,如果這麼做了,那麼就非法了。這裡使用者空間相當于儲戶,核心空間相當于銀行職員,而硬碟相當于金庫,也就是使用者空間中的程序沒法直接操作讀寫硬碟中的資料,我們需要通過核心空間來處理,這樣對于這兩個概念應該會容易了解些。

空間 描述
使用者空間 是非特權區域,在該區域執行的代碼不能直接通路硬體裝置,正常程序就在本區域執行,JVM就是正常程序,是以JVM程序駐守在使用者空間
核心空間 是作業系統所在區域,有特别的權利:能與裝置控制器通訊,控制着使用者區域程序的運作狀态等等,最重要的是,所有I/O都直接或間接的通過核心空間

2.普通IO操作

  了解了使用者空間和核心空間的概念和作用後我們來看下普通IO的執行原理。

Java檔案讀寫原理和虛拟記憶體

  根據上圖,當程序請求一個I/O操作,它會執行一個系統(open() , read() , writer() , close())調用将控制權移交給核心。當核心以這種方式被調用,它随即采取任何必要步驟,找到程序所需資料,并把資料傳送到使用者空間内指定的緩沖區中,這時正常程序就可以對緩沖區中的資料處理操作了,而核心試圖對資料進行高速緩存或預讀取,是以程序所需資料可能已經在核心空間裡了,如果是這樣,該資料隻需簡單地拷貝出來即可,如果資料不在核心空間,則程序被挂起,核心着手把資料讀進内場。

問題

  資料從核心空間拷貝到使用者空間似乎多餘,為什麼不直接讓磁盤把資料送到使用者空間的緩沖區呢?

  1. 硬碟通常不能直接通路使用者空間
  2. 磁盤基于塊存儲的硬體裝置操作的固定大小的資料塊,使用者程序請求的可能是任意大小或者非對齊的資料塊,在這兩者資料互動過程中核心負責資料的分解、再組合工作,起到一個中間人的角色。

3.虛拟記憶體

  通過上面的介紹,我們知道當應用程式需要讀取檔案的時候,核心首先通過DMA技術将檔案内容從磁盤讀入核心中的buffer,然後Java應用程序再從核心的buffer将資料讀取到應用程式的buffer。也就是有兩次的檔案複制,為了提升I/O效率和處理能力,作業系統采用虛拟記憶體的機制。虛拟記憶體意為使用虛假(或虛拟)位址取代實體(硬體RAM)記憶體位址。這樣做好處頗多,總結起來可分為兩大類:

  1. 一個以上的虛拟位址可指向同一個實體記憶體位址。
  2. 虛拟記憶體空間可大于實際可用的硬體記憶體
Java檔案讀寫原理和虛拟記憶體

  這樣做的好處是省去了核心與使用者空間的往來拷貝。

3.1 一個以上的虛拟位址可指向同一個實體記憶體位址

  在進行IO操作時就可以将使用者空間的buffer區和核心空間的buffer區指向同一個實體記憶體。這樣使用者空間的程式就不需要再去核心空間再取回資料,而是可以直接通路,節省記憶體空間。

Java檔案讀寫原理和虛拟記憶體

3.2 虛拟記憶體空間可大于實際可用的硬體記憶體

  當使用者程式通路記憶體位址時,一般的操作如下:首先虛拟記憶體系統會到實體記憶體去查找該虛拟位址是否存在。如果存在,如A1,則直接從實體記憶體中讀取;如果不存在,如A4則會抛出一個信号。這時虛拟記憶體系統會去磁盤空間中找,找到後再按一定的政策,将其置入到記憶體中,如将B2和A4交換。然後由使用者程式就可以使用A4中的資料。這樣就保證了使用者程式可以讀取一些大型的檔案。

Java檔案讀寫原理和虛拟記憶體

  從本質上說,實體記憶體充當了分頁區的高速緩存;而所謂分頁區,即從實體記憶體置換出來,轉而存儲于磁盤上的記憶體頁面.

  把記憶體頁大小設定為磁盤塊大小的倍數,這樣核心就可直接向磁盤控制硬體釋出指令,把記憶體頁寫入磁盤,在需要時再重新裝入。結果是,所有磁盤 I/O 都在頁層面完成。對于采用分頁技術的,現代作業系統而言,這也是資料在磁盤與實體記憶體之間往來的唯一方式

Java檔案讀寫原理和虛拟記憶體

3.3記憶體管理單元

  現代 CPU 包含一個稱為記憶體管理單元(MMU)的子系統,邏輯上位于CPU 與實體記憶體之間。該裝置包含虛拟位址向實體記憶體位址轉換時所需映射資訊。當 CPU 引用某記憶體位址時,MMU負責确定該位址所在頁(往往通過對位址值進行移位或屏蔽位操作實作),并将虛拟頁号轉換為實體頁号(這一步由硬體完成,速度極快)。如果目前不存在與該虛拟頁形成有效映射的實體記憶體頁,MMU會向CPU 送出一個頁錯誤。

繼續閱讀