Java 自動擴容Mmap數據寫入性能測試

背景:

低配設備I/O優化,利用mmap實現日誌的管理。

 

測試代碼:

public class MmapWriter {

    private static final int BUF_SIZE = 4096;
    private  File mFile;
    private FileChannel mChannel;
    private RandomAccessFile raf;
    private long GROVE_SPACE = 1 * 1024 * 1024L;
    private MappedByteBuffer buffer;
    private long writeSize = 0L;

    public MmapWriter(String path) {  // avg = 42612619225 /100 ns
        mFile = new File(path);
        try {
            if(mFile.exists()){
                mFile.delete();
            }
            raf = new RandomAccessFile(mFile, "rws");
            mChannel = raf.getChannel();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        }
    }


    public static void main(String[] args) {
        long millis = System.currentTimeMillis();
        System.out.println("--開始寫入--" );
        try {
            for (int i = 0; i < 100; i++) {
                fisTest();  //buf=8192 (33355+33123)/200   | buf=2048 41929  | buf=4096
              //   mmapTest(); //buf=8192  (26417 + 25735)/200     |buf=2048  41685 |buf = 4096 31874
            }
            //mmap 相比普通的讀寫,快70ms左右
        } catch (Exception e) {
            e.printStackTrace();
        }finally {
            System.out.println("--寫入完成-- cost="+(System.currentTimeMillis() - millis));
        }
    }

    private static void fisTest(){
        File file = new File("/Users/wiseyang/Downloads/FFmpeg從入門到精通.pdf");
        FileInputStream fis = null;
        try {
            fis = new FileInputStream(file);
            File outFile = new File("FFmpeg從入門到精通.pdf");
            if(outFile.exists()){
                outFile.delete();
            }
            BufferedOutputStream bos = new BufferedOutputStream(new FileOutputStream(outFile));
            byte[] buf = new byte[BUF_SIZE];
            int len;
            while ((len = fis.read(buf,0,buf.length))!=-1){
                bos.write(buf,0,len);
            }
            bos.close();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }

    }

    private static void mmapTest() throws IOException {
        MmapWriter writer = new MmapWriter("FFmpeg從入門到精通.pdf");
        File file = new File("/Users/wintertian/Downloads/FFmpeg從入門到精通.pdf");
        FileInputStream fis = new FileInputStream(file);
        byte[] buf = new byte[BUF_SIZE];
        int len;
        while ((len = fis.read(buf,0,buf.length))!=-1){
            writer.writeBuffer(buf,0,len);
        }
        writer.stopRecord();
    }

    public void writeBuffer(byte[] frame, int pos, int bufferSize) {
        RandomAccessFile raf = this.raf;
        if (mChannel == null || frame == null || bufferSize <= 0) {
            return;
        }
        try {

            int n = 1;
            while ((buffer == null) || (writeSize + bufferSize) >= mChannel.size()) {
                buffer = mChannel.map(FileChannel.MapMode.READ_WRITE, writeSize, GROVE_SPACE * n);
//mmap 需要擴容,不然會寫入失敗
                n++;
            }

            buffer.put(frame, pos, bufferSize);
            writeSize += bufferSize;

        } catch (IOException e) {
            e.printStackTrace();
        }catch (BufferOverflowException e){
            e.printStackTrace();
        }
    }

    @Override
    protected void finalize() throws Throwable {
        super.finalize();
        stopRecord();
    }

    public void stopRecord() {
        RandomAccessFile raf = this.raf;
        if (raf != null) {
            try {
                if (mChannel != null) {
                    mChannel.truncate(writeSize);
                }
                raf.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        this.raf = null;
    }
}

 

結論:

buffer越大,mmap寫入越明顯

 // fisTest();  //buf=8192 (33355+33123)/200         | buf=2048 41929  | buf=4096 40110
//  mmapTest();  //buf=8192  (26417 + 25735)/200     |buf=2048  41685  | buf=4096 31874

 

mmap進行日誌管理的優缺點:

優點:斷電保護,寫入速度相對較快

缺點:

需要經常擴容,如果寫入前crash,容易造成空文件,造成磁盤空間浪費(當然可以改善,就是每次寫入時記錄寫入的位置,下次從寫入位置開始查找空數據)

 

 

 

 

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章