Memory Mapped File
在java早期版本中,使用FileSystem傳統的API來訪問系統文件。這種場景下,JVM發起read()、write()系統調用從OS kernel到JVM傳輸數據。JVM使用它的內存空間加載、處理文件。如果文件比較大,處理起來比較慢。OS使用頁的方式處理文件,而JVM使用字節流的方式,不能匹配文件頁,因此需要從OS內核空間拷貝文件的內容到JVM空間。從jdk1.4開始,提供了MappedByteBuffer,用於幫助建立一個從JVM空間到OS文件系統頁的映射的虛擬內存。這種方式避免了因爲拷貝文件內容的帶來的開銷。OS使用虛擬內存在內核空間之外緩存文件,可以被非內核進行所共享。java直接映射文件頁到MappedByteBuffer,然後處理文件,不需要將其加載到JVM裏面。
MappedByteBuffer直接使用FileChannel的map方法,對虛擬內存的內容進行映射。MappedByteBuffer對象工作起來像buffer,但是它的數據存儲在虛擬內存的文件裏。get()方法可以從文件裏獲取數據。put()方法更新數據,對文件的其他讀者修改可見。
這樣做的好處,如下:
- JVM直接在虛擬內存上處理,不需要發起read()、write()系統調用。
- JVM不需要在它的內存空間中加載文件,處理大數據文件更有效率。
- OS基本上只需要關注虛擬內存的讀寫,不需要使用JVM。
- 提供文件的部分映射。
- 虛擬內存的文件數據不需要buffer進行傳遞。
如果增加了準備寫入的文件大小,並且大於了文件本身的大小,導致MappedByteBuffer 在寫模式中匹配的大小變得更大,但是在讀模式中會拋出IOException。
提供瞭如下三種映射模式:
- READ_ONLY: Read only
- READ_WRITE: Read and update the file
- PRIVATE: Change in MappedByteBuffer will not reflect to File.
映射同一個文件的多個MappedByteBuffer之間不可見可以通過PRIVATE映射模式,創建私有的副本。
如果在READ_ONLY模式中寫,會拋出NonWritableChannelException。如果讀取的channel沒有開放,此時的讀取會拋出NonReadableChannelException。
e.g.