2013-05-28 71 views
-1

我正在嘗試做一些性能改進,並且正在尋找使用內存映射文件來寫入數據。我做了一些測試,出人意料的是,MappedByteBuffer似乎比分配直接緩衝區慢。我無法清楚地理解爲什麼會這樣。有人可以暗示幕後會發生什麼?以下是我的測試結果:MappedByteBuffer與ByteBuffer的性能

我正在分配32KB緩衝區。在開始測試之前,我已經創建了大小爲3Gigs的文件。所以,增加文件不是問題。

Test results DirectBuffer vs MappedByteBuffer

我加入,我用這個性能測試的代碼。任何關於這種行爲的輸入/解釋都非常感謝。

import java.io.BufferedWriter; 
import java.io.File; 
import java.io.FileWriter; 
import java.io.IOException; 
import java.io.RandomAccessFile; 
import java.nio.ByteBuffer; 
import java.nio.MappedByteBuffer; 
import java.nio.channels.FileChannel; 
import java.nio.channels.FileChannel.MapMode; 

public class MemoryMapFileTest { 

    /** 
    * @param args 
    * @throws IOException 
    */ 
    public static void main(String[] args) throws IOException { 

     for (int i = 0; i < 10; i++) { 
      runTest(); 
     } 

    } 

    private static void runTest() throws IOException { 

     // TODO Auto-generated method stub 
     FileChannel ch1 = null; 
     FileChannel ch2 = null; 
     ch1 = new RandomAccessFile(new File("S:\\MMapTest1.txt"), "rw").getChannel(); 
     ch2 = new RandomAccessFile(new File("S:\\MMapTest2.txt"), "rw").getChannel(); 

     FileWriter fstream = new FileWriter("S:\\output.csv", true); 
     BufferedWriter out = new BufferedWriter(fstream); 


     int[] numberofwrites = {1,10,100,1000,10000,100000}; 
     //int n = 10000; 
     try { 
      for (int j = 0; j < numberofwrites.length; j++) { 
       int n = numberofwrites[j]; 
       long estimatedTime = 0; 
       long mappedEstimatedTime = 0; 

       for (int i = 0; i < n ; i++) { 
        byte b = (byte)Math.random(); 
        long allocSize = 1024 * 32; 

        estimatedTime += directAllocationWrite(allocSize, b, ch1); 
        mappedEstimatedTime += mappedAllocationWrite(allocSize, b, i, ch2); 

       } 

       double avgDirectEstTime = (double)estimatedTime/n; 
       double avgMapEstTime = (double)mappedEstimatedTime/n; 
       out.write(n + "," + avgDirectEstTime/1000000 + "," + avgMapEstTime/1000000); 
       out.write("," + ((double)estimatedTime/1000000) + "," + ((double)mappedEstimatedTime/1000000)); 
       out.write("\n"); 
       System.out.println("Avg Direct alloc and write: " + estimatedTime); 
       System.out.println("Avg Mapped alloc and write: " + mappedEstimatedTime); 

      } 


     } finally { 
      out.write("\n\n"); 
      if (out != null) { 
       out.flush(); 
       out.close(); 
      } 

      if (ch1 != null) { 
       ch1.close(); 
      } else { 
       System.out.println("ch1 is null"); 
      } 

      if (ch2 != null) { 
       ch2.close(); 
      } else { 
       System.out.println("ch2 is null"); 
      } 

     } 
    } 


    private static long directAllocationWrite(long allocSize, byte b, FileChannel ch1) throws IOException { 
     long directStartTime = System.nanoTime(); 
     ByteBuffer byteBuf = ByteBuffer.allocateDirect((int)allocSize); 
     byteBuf.put(b); 
     ch1.write(byteBuf); 
     return System.nanoTime() - directStartTime; 
    } 

    private static long mappedAllocationWrite(long allocSize, byte b, int iteration, FileChannel ch2) throws IOException { 
     long mappedStartTime = System.nanoTime(); 
     MappedByteBuffer mapBuf = ch2.map(MapMode.READ_WRITE, iteration * allocSize, allocSize); 
     mapBuf.put(b); 
     return System.nanoTime() - mappedStartTime; 
    } 

} 
+0

To添加更多的清晰度,當寫入文件時,我想了解MappedByteBuffer是否比只使用ByteBuffer和使用FileChannel執行寫入更好。就我的閱讀而言,MappeByteBuffers應該表現得更好,因爲它避免了明確的JNI寫入調用 – Sudoer

回答

6

您正在測試錯誤的東西。這不是在任何情況下如何編寫代碼。您應該分配一次緩衝區,並且不斷更新其內容。您在寫入時間中包含分配時間。無效。

+0

嗯,我是故意這麼做的。我的分配方案創建不同大小的緩衝區。但是,如果我需要一個更大的緩衝區,我需要扔更小的緩衝區來分配新的緩衝區。因此,我將其納入我的測試。 如果我排除緩衝區創建,內存映射緩衝區執行更差。我試圖找到一個解釋。 – Sudoer

+2

解釋是,對文件進行內存映射比創建直接的「ByteBuffer」需要更長的時間。我不知道你期待什麼樣的答案,但就是這樣。大概需要更多的處理才能將文件映射到內存中,而不是分配未映射的內存。我不知道爲什麼這會被認爲是令人驚訝的。不管動機如何,這都是糟糕的編程。 – EJP

0

將數據交換到磁盤是MappedByteBuffer比DirectByteBuffer慢的主要原因。 使用直接緩衝區(包括MappedByteBuffer)分配和解除分配的代價很高,這是兩個示例的代價,因此寫入磁盤的唯一區別在於MappedByteBuffer,但不是直接字節緩衝區