NIO 之 MappedByteBuffer
可參考: MappedByteBuffer以及ByteBufer的底層原理
概述
Bytebuffer分為兩種:間接地和直接的,所謂直接就是指MappedByteBuffer,直接使用內(nèi)存映射(java的話就意味著在JVM之外分配虛擬地址空間);而間接的ByteBuffer是在JVM的堆上面的。間接緩沖區(qū)就是我們通常說的堆緩沖區(qū)。
直接緩沖區(qū) java內(nèi)部是使用 DirectByteBuffer 來實現(xiàn)的。
堆緩沖區(qū)java內(nèi)部是使用 HeapByteBuffer 來實現(xiàn)的。
映射的字節(jié)緩沖區(qū)(MappedByteBuffer ) 不提供關閉或銷毀方法。也就是說,創(chuàng)建完直接緩沖區(qū),就一直有效,直到緩沖區(qū)本身被垃圾收集。
映射字節(jié)緩沖區(qū)的內(nèi)容可以在任何時間改變,例如,如果映射的文件的對應區(qū)域的內(nèi)容由該程序或其他程序改變。無論這種變化是否發(fā)生,當它們發(fā)生時,都是依賴于操作系統(tǒng)的,因此不明確。
映射的字節(jié)緩沖區(qū)的全部或部分可能在任何時間變得不可訪問,例如映射的文件被截斷。試圖訪問映射字節(jié)緩沖區(qū)的不可訪問區(qū)域不會改變緩沖區(qū)的內(nèi)容,并且會導致在訪問時或稍后某個時間拋出一個未指定的異常。因此,強烈建議采取適當?shù)念A防措施,以避免由該程序或由同時運行的程序操縱映射文件,除了讀取或?qū)懭胛募膬?nèi)容。
MappedByteBuffer 類結構
public abstract class MappedByteBuffer extends ByteBuffer {public final MappedByteBuffer load( )public final boolean isLoaded( )public final MappedByteBuffer force( ) }MappedByteBuffer 繼承了 ByteBuffer 。
load() 方法
load( )方法會整個文件加載到內(nèi)存中。
此方法盡最大努力確保當它返回時,該緩沖區(qū)的內(nèi)容駐留在物理內(nèi)存中。調(diào)用此方法可能會導致一些頁面錯誤和I/O操作發(fā)生。
操作系統(tǒng)會采用虛擬內(nèi)存映射,把緩沖區(qū)和文件建立虛擬內(nèi)存映射。此映射使得操作系統(tǒng)的底層虛擬內(nèi)存子系統(tǒng)可以根據(jù)需要將文件中相應區(qū)塊的數(shù)據(jù)讀進內(nèi)存。已經(jīng)在內(nèi)存中或通過驗證的頁會占用實際內(nèi)存空間,并且在它們被讀進 RAM 時會擠出最近較少使用的其他內(nèi)存頁。(swap in,swap out)
在一個映射緩沖區(qū)上調(diào)用 load( )方法會是一個代價高的操作,因為它會導致大量的頁調(diào)入(page-in),具體數(shù)量取決于文件中被映射區(qū)域的實際大小。然而,load( )方法返回并不能保證文件就會完全加載到內(nèi)存,這是由于請求頁面調(diào)入是動態(tài)的。具體結果會因某些因素而有所差異,這些因素包括:操作系統(tǒng)、文件系統(tǒng),可用 Java 虛擬機內(nèi)存,最大 Java 虛擬機內(nèi)存,垃圾收集器實現(xiàn)過程等等。
請小心使用 load( )方法,它可能會導致您不希望出現(xiàn)的結果。該方法的主要作用是為提前加載文件埋單,以便后續(xù)的訪問速度可以盡可能的快。
對于那些要求近乎實時訪問的程序,解決方案就是預加載。但是請記住,不能保證全部頁都加載到內(nèi)存,不管怎樣,之后可能還會有頁調(diào)入發(fā)生(操作系統(tǒng)自己維護,依賴操作系統(tǒng)的實現(xiàn))。內(nèi)存頁什么時候swap in 和 swap out 受多個因素影響,這些因素中的許多都是不受 Java 虛擬機控制的。
JDK 1.4 的 NIO 并沒有提供一個可以把頁面固定到物理內(nèi)存上的API,盡管一些操作系統(tǒng)是支持這樣做的。對于大多數(shù)程序,特別是交互性的或其他事件驅(qū)動(event-driven)的程序而言,為提前加載文件消耗資源是不劃算的。在實際訪問時分攤頁調(diào)入開銷才是更好的選擇。讓操作系統(tǒng)根據(jù)需要來調(diào)入頁意味著不訪問的頁永遠不需要被加載。同預加載整個被映射的文件相比,這很容易減少 I/O 活動總次數(shù)。操作系統(tǒng)已經(jīng)有一個復雜的內(nèi)存管理系統(tǒng)了,就讓它來替您完成此工作吧!
isLoaded() 方法
我們可以通過調(diào)用 isLoaded( )方法來判斷一個被映射的文件是否完全加載內(nèi)存了。
如果該方法返回ture,意味著該緩沖區(qū)中的所有數(shù)據(jù)很可能完全加載到物理內(nèi)存中了,因此可以在不產(chǎn)生任何虛擬內(nèi)存頁錯誤或I/O操作的情況下訪問。
不過,該方法返回false,并不一定意味著緩沖區(qū)的內(nèi)容沒有加載到物理內(nèi)存中。
返回值是一個提示,而不是一個保證,因為底層操作系統(tǒng)在調(diào)用該方法返回的時候可能已經(jīng)分出了一些緩沖區(qū)的數(shù)據(jù)。
force() 方法
該方法會強制將此緩沖區(qū)上的任何更改寫入映射到永久磁盤存儲器上。
如果映射到該緩沖區(qū)的文件駐留在本地存儲設備上,那么當該方法返回時,它保證對創(chuàng)建的緩沖區(qū)進行的所有更改,或者自上次調(diào)用該方法后,將被寫入該設備。
如果文件不駐留在本地設備上,則不提供這樣的保證。
當用 MappedByteBuffer 對象來更新一個文件,您應該總是使用 MappedByteBuffer.force( )而非 FileChannel.force( ),因為通道對象可能
不清楚通過映射緩沖區(qū)做出的文件的全部更改。MappedByteBuffer 沒有不更新文件元數(shù)據(jù)的選項——元數(shù)據(jù)總是會同時被更新的。
如果映射是以 MapMode.READ_ONLY 或 MAP_MODE.PRIVATE 模式建立的,那么調(diào)用 force( )
方法將不起任何作用,因為永遠不會有更改需要應用到磁盤上(但是這樣做也是沒有害處的)。
想了解更多精彩內(nèi)容請關注我的公眾號
本人簡書blog地址:http://www.jianshu.com/u/1f0067e24ff8????
點擊這里快速進入簡書
GIT地址:http://git.oschina.net/brucekankan/
點擊這里快速進入GIT
總結
以上是生活随笔為你收集整理的NIO 之 MappedByteBuffer的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: NIO 之 Buffer 图解
- 下一篇: NIO 之 Channel