1. 程式人生 > 實用技巧 >資料開發_Java中記憶體對映檔案

資料開發_Java中記憶體對映檔案

記憶體對映檔案

1.FileChannel 和外界的介質進行互動
   有3種模式:READ_ONLY(只讀)、READ_WRITE(讀寫)、PRIVATE(私有,用於copy-on-write)
   1.MappedByteBuffer一旦建立,就與建立它的通道無關,即通道關閉時,不影響該緩衝器
     FileChannel channel = FileChannel.open(path,options);
    2. MappedByteBuffer map
2.緩衝區的操作
   緩衝區的操作可以檢視Java API java.nio.Buffer
 3.加鎖
     多個執行緒訪問的情況下考慮

memory-map files

Java Memory-Mapped File所使用的記憶體分配在實體記憶體而不是JVM堆記憶體,且分配在OS核心
在一般的檔案讀寫中,會有兩次資料拷貝,一次是從硬碟拷貝到作業系統核心,另一次是從作業系統核心拷貝到使用者態的應用程式。
而在記憶體對映檔案中,一般情況下,只有一次拷貝,且記憶體分配在作業系統核心,應用程式訪問的就是作業系統的核心記憶體空間。
 Java語言通過java.nio包支援記憶體對映檔案和IO
 對於一般的檔案讀寫不需要使用記憶體對映檔案,
     但如果處理的是大檔案,要求極高的讀寫效率,
     比如資料庫系統或繁忙的電子交易系統,
     或者需要在不同程式間進行共享和通訊,那就可以考慮記憶體對映檔案
 	讀寫記憶體對映檔案是作業系統來負責的,因此,即使你的Java程式在寫入記憶體後就掛掉了,只要作業系統工作正常,資料就會寫入磁碟
 	Direct位元組快取比non-direct位元組快取效能要好

程式碼示例

import java.nio.ByteBuffer;
public class ByteBufferExp {
    public static void main(String args[]) {
        // 啟動JAVA虛擬機器時使用引數-Xmx100m
        Runtime run = Runtime.getRuntime();
        System.out.println("最大記憶體MB = " +  run.maxMemory()/1024/1024);
        System.out.println("已分配記憶體 = " + run.totalMemory()/1024/1024);
        System.out.println("已分配記憶體中的剩餘空間 = " + run.freeMemory()/1024/1024);
        System.out.println("已分配記憶體中的使用空間 = " + (run.totalMemory() -run.freeMemory())/1024/1024 );
        System.out.println("剩餘最大可用於  記憶體 = " + (run.maxMemory()+ run.freeMemory()-run.totalMemory())/1024/1024);

        System.out.println("----------allocate--------");
        //4個靜態工廠方法來獲得ByteBuffer的例項
        System.out.println("before alocate 即已分配記憶體中的剩餘空間:" + run.freeMemory()/1024/1024);
        // 從 堆空間 中分配一個容量大小為capacity的byte陣列作為緩衝區的byte資料儲存器
        //將建立一個容量為 26位元組的ByteBuffer,如果發現建立的緩衝區容量太小,唯一的選擇就是重新建立一個大小合適的緩衝區.
        ByteBuffer buffer = ByteBuffer.allocate(26*1024*1024);
        // 緩衝區都有4個屬性:capacity、limit、position
        // capacity 容量,即可以容納的最大資料量;在緩衝區建立時被設定並且不能改變
        System.out.println("緩衝區 buffer = " + buffer);
        System.out.println("緩衝區alocate 之後:" + run.freeMemory()/1024/1024);

        //通過作業系統來建立記憶體塊用作緩衝區  這部分直接用的系統記憶體,所以對JVM的記憶體沒有影響
        ByteBuffer directBuffer = ByteBuffer.allocateDirect(100*1024*1024);
        System.out.println("直接緩衝區 directBuffer = " + directBuffer);
        System.out.println(" 直接緩衝區 direct alocate 之後:" + run.freeMemory()/1024/1024);

        System.out.println("----------Test wrap--------");
        // 通過包裝的方法建立的緩衝區保留了被包裝陣列內儲存的資料
        byte[] bytes = new byte[32];
        buffer = ByteBuffer.wrap(bytes);
        System.out.println("緩衝區wrap buffer = " + buffer);
        System.out.println("wrap buffer 之後:" + run.freeMemory()/1024/1024);

        // 以指定偏移量和長度,這個offset也就是包裝後byteBuffer的position,
        // 而length呢就是limit-position的大小,從而我們可以得到limit的位置為length+position(offset)
        buffer = ByteBuffer.wrap(bytes, 10, 10);
        System.out.println("緩衝區wrap buffer = " + buffer);
        System.out.println("wrap buffer 之後:" + run.freeMemory()/1024/1024);
       }
    }



A byte buffer,一個位元組緩衝區
 Objects of this class may reside almost entirely in memory-map files. 
 That is the primary reason for them to be considered immutable, since no reallocation is possible when using2020/11/20 memory-mapped files.