Java文件讀寫原理和虛擬內(nèi)存
后面打算系統(tǒng)性的介紹下NIO和Netty的內(nèi)容,因為這塊內(nèi)容也是每個程序員必須要掌握的內(nèi)容,而在介紹NIO之前我們需要先了解下一些前置的知識
1.內(nèi)核空間和用戶空間
這兩個概念對于初次接觸的小伙伴來說并不是很好理解,舉個簡單例子如下圖:
上圖中的儲戶是沒法直接從金庫中存錢獲取取錢的,如果這么做了,那么就非法了。這里用戶空間相當(dāng)于儲戶,內(nèi)核空間相當(dāng)于銀行職員,而硬盤相當(dāng)于金庫,也就是用戶空間中的進(jìn)程沒法直接操作讀寫硬盤中的數(shù)據(jù),我們需要通過內(nèi)核空間來處理,這樣對于這兩個概念應(yīng)該會容易理解些。
2.普通IO操作
了解了用戶空間和內(nèi)核空間的概念和作用后我們來看下普通IO的執(zhí)行原理。
根據(jù)上圖,當(dāng)進(jìn)程請求一個I/O操作,它會執(zhí)行一個系統(tǒng)(open() , read() , writer() , close())調(diào)用將控制權(quán)移交給內(nèi)核。當(dāng)內(nèi)核以這種方式被調(diào)用,它隨即采取任何必要步驟,找到進(jìn)程所需數(shù)據(jù),并把數(shù)據(jù)傳送到用戶空間內(nèi)指定的緩沖區(qū)中,這時常規(guī)進(jìn)程就可以對緩沖區(qū)中的數(shù)據(jù)處理操作了,而內(nèi)核試圖對數(shù)據(jù)進(jìn)行
高速緩存或預(yù)讀取
,因此進(jìn)程所需數(shù)據(jù)可能已經(jīng)在內(nèi)核空間里了,如果是這樣,該數(shù)據(jù)只需簡單地拷貝出來即可,如果數(shù)據(jù)不在內(nèi)核空間,則進(jìn)程被掛起,內(nèi)核著手把數(shù)據(jù)讀進(jìn)內(nèi)場。
問題
數(shù)據(jù)從內(nèi)核空間拷貝到用戶空間似乎多余,為什么不直接讓磁盤把數(shù)據(jù)送到用戶空間的緩沖區(qū)呢?
硬盤通常不能直接訪問用戶空間
磁盤基于塊存儲的硬件設(shè)備操作的固定大小的數(shù)據(jù)塊,用戶進(jìn)程請求的可能是任意大小或者非對齊的數(shù)據(jù)塊,在這兩者數(shù)據(jù)交互過程中內(nèi)核負(fù)責(zé)數(shù)據(jù)的分解、再組合工作,起到一個中間人的角色。
3.虛擬內(nèi)存
通過上面的介紹,我們知道當(dāng)應(yīng)用程序需要讀取文件的時候,內(nèi)核首先通過DMA技術(shù)將文件內(nèi)容從磁盤讀入內(nèi)核中的buffer,然后Java應(yīng)用進(jìn)程再從內(nèi)核的buffer將數(shù)據(jù)讀取到應(yīng)用程序的buffer。也就是有
兩次
的文件復(fù)制,為了提升I/O效率和處理能力,操作系統(tǒng)采用虛擬內(nèi)存的機(jī)制。虛擬內(nèi)存意為使用虛假(或虛擬)地址取代物理(硬件RAM)內(nèi)存地址。這樣做好處頗多,總結(jié)起來可分為兩大類:
一個以上的虛擬地址可指向同一個物理內(nèi)存地址。
虛擬內(nèi)存空間可大于實際可用的硬件內(nèi)存
這樣做的好處是省去了內(nèi)核與用戶空間的往來拷貝。
3.1 一個以上的虛擬地址可指向同一個物理內(nèi)存地址
在進(jìn)行IO操作時就可以將用戶空間的buffer區(qū)和內(nèi)核空間的buffer區(qū)指向同一個物理內(nèi)存。這樣用戶空間的程序就不需要再去內(nèi)核空間再取回數(shù)據(jù),而是可以直接訪問,節(jié)省內(nèi)存空間。
3.2 虛擬內(nèi)存空間可大于實際可用的硬件內(nèi)存
當(dāng)用戶程序訪問內(nèi)存地址時,一般的操作如下:首先虛擬內(nèi)存系統(tǒng)會到物理內(nèi)存去查找該虛擬地址是否存在。如果存在,如A1,則直接從物理內(nèi)存中讀取;如果不存在,如A4則會拋出一個信號。這時虛擬內(nèi)存系統(tǒng)會去磁盤空間中找,找到后再按一定的策略,將其置入到內(nèi)存中,如將B2和A4交換。然后由用戶程序就可以使用A4中的數(shù)據(jù)。這樣就保證了用戶程序可以讀取一些大型的文件。
從本質(zhì)上說,
物理內(nèi)存
充當(dāng)了
分頁區(qū)
的
高速緩存
;而所謂分頁區(qū),即從物理內(nèi)存置換出來,轉(zhuǎn)而存儲于磁盤上的內(nèi)存頁面.
把內(nèi)存頁大小設(shè)定為磁盤塊大小的倍數(shù),這樣內(nèi)核就可直接向磁盤控制硬件發(fā)布命令,把內(nèi)存頁寫入磁盤,在需要時再重新裝入。結(jié)果是,所有磁盤 I/O 都在頁層面完成。對于采用分頁技術(shù)的,現(xiàn)代操作系統(tǒng)而言,這也是數(shù)據(jù)在磁盤與物理內(nèi)存之間往來的唯一方式
3.3內(nèi)存管理單元
現(xiàn)代 CPU 包含一個稱為內(nèi)存管理單元(MMU)的子系統(tǒng),邏輯上位于CPU 與物理內(nèi)存之間。該設(shè)備包含虛擬地址向物理內(nèi)存地址轉(zhuǎn)換時所需映射信息。當(dāng) CPU 引用某內(nèi)存地址時,MMU負(fù)責(zé)確定該地址所在頁(往往通過對地址值進(jìn)行移位或屏蔽位操作實現(xiàn)),并將虛擬頁號轉(zhuǎn)換為物理頁號(這一步由硬件完成,速度極快)。如果當(dāng)前不存在與該虛擬頁形成有效映射的物理內(nèi)存頁,MMU會向CPU 提交一個頁錯誤。
頁錯誤隨即產(chǎn)生一個陷阱(類似于系統(tǒng)調(diào)用),把控制權(quán)移交給內(nèi)核,附帶導(dǎo)致錯誤的虛擬地址信息,然后內(nèi)核采取步驟驗證頁的有效性。內(nèi)核會安排頁面調(diào)入操作,把缺失的頁內(nèi)容讀回物理內(nèi)存。這往往導(dǎo)致別的頁被移出物理內(nèi)存,好給新來的頁讓地方。在這種情況下,如果待移出的頁已經(jīng)被碰過了(自創(chuàng)建或上次頁面調(diào)入以來,內(nèi)容已發(fā)生改變),還必須首先執(zhí)行頁面調(diào)出,把頁內(nèi)容拷貝到磁盤上的分頁區(qū)。
如果所要求的地址不是有效的虛擬內(nèi)存地址(不屬于正在執(zhí)行的進(jìn)程的任何一個內(nèi)存段),則該頁不能通過驗證,段錯誤隨即產(chǎn)生。于是,控制權(quán)轉(zhuǎn)交給內(nèi)核的另一部分,通常導(dǎo)致的結(jié)果就是進(jìn)程被強(qiáng)令關(guān)閉。
一旦出錯的頁通過了驗證,MMU 隨即更新,建立新的虛擬到物理的映射(如有必要,中斷被移出頁的映射),用戶進(jìn)程得以繼續(xù)。造成頁錯誤的用戶進(jìn)程對此不會有絲毫察覺,一切都在不知不覺中進(jìn)行
Java 虛擬化
版權(quán)聲明:本文內(nèi)容由網(wǎng)絡(luò)用戶投稿,版權(quán)歸原作者所有,本站不擁有其著作權(quán),亦不承擔(dān)相應(yīng)法律責(zé)任。如果您發(fā)現(xiàn)本站中有涉嫌抄襲或描述失實的內(nèi)容,請聯(lián)系我們jiasou666@gmail.com 處理,核實后本網(wǎng)站將在24小時內(nèi)刪除侵權(quán)內(nèi)容。