2013-05-28 4 views
-1

Я пытаюсь сделать несколько улучшений производительности и хочу использовать файлы с отображением памяти для записи данных. Я сделал несколько тестов и, на удивление, MappedByteBuffer кажется медленнее, чем выделение прямых буферов. Я не могу четко понять, почему это так. Может кто-нибудь угодить намеку на то, что может происходить за кулисами? Ниже приведены мои результаты:Производительность MappedByteBuffer vs ByteBuffer

Я выделяю буферы 32 КБ. Я уже создал файлы с размерами 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, но не с прямым байтовым буфером

Смежные вопросы