2016-05-25 5 views
1

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

Я hava файл «dataFile» в 1GB, который заполняется целыми числами.

private final File dataFile = new File("~/testfile"); 
private final int intNum = 1024 * 1024 * 1024/4; // 1GB Integers 

@Test 
public void writeFile() throws Exception { 
    DataOutputStream dos = new DataOutputStream(new BufferedOutputStream(new FileOutputStream(dataFile))); 
    for (int i = 0; i < intNum; i++) { 
     dos.writeInt(RandomUtils.nextInt()); 
    } 
    dos.close(); 
} 

и метод о чтении его

// read this dataFile in a loop with fixed map size 
private void bufferSizePerformanceTest(final int buffSize) throws Exception { 
    Stopwatch stopwatch = Stopwatch.createStarted(); 
    FileChannel fc = new RandomAccessFile(dataFile, "r").getChannel(); 
    MappedByteBuffer buffer; 
    final int readPerLoop = buffSize/4; 
    int currentLen = 0; 
    int readCount = 0; 
    for (int i = 1; ; i++) { 
     int i1 = i * buffSize; 
     if (i1 >= dataFile.length()) { 
      buffer = fc.map(FileChannel.MapMode.READ_ONLY, currentLen, dataFile.length() - currentLen); 
      for (int j = 0; j < readPerLoop; j++) { 
       buffer.getInt(); 
       readCount++; 
      } 
      break; 
     } else { 
      buffer = fc.map(FileChannel.MapMode.READ_ONLY, currentLen, buffSize); 
      currentLen = i1; 
     } 

     for (int j = 0; j < readPerLoop; j++) { 
      buffer.getInt(); 
      readCount++; 
     } 
    } 
    fc.close(); 
//  ByteBufferUtil.releaseByteBuffer(buffer); 
//  System.gc(); 
    System.out.println("readCount : " + readCount + " raf buffer size " + getMBytes(buffSize) + " MB : " + stopwatch.elapsed(TimeUnit.MILLISECONDS)); 
} 

Изменение buffSize тестовый

private static int getMBytes(int bytes) { 
    return bytes/1024/1024; 
} 

// get the power of 2 by n 
private static int getM(int n) { 
    return (int) (Math.log10(n)/Math.log10(2)); 
} 

@Test 
public void testBuffSizeReadPerformance() throws Exception { 
    System.out.println(ManagementFactory.getRuntimeMXBean().getName()); 
    for (int i = 0; i <= getM(1024); i++) { 
     Thread.sleep(1000); 
     bufferSizePerformanceTest((int) (Math.pow(2, i) * 1024 * 1024)); 
    } 
} 

Variation Выходы:

[email protected] 
readCount : 268435456 raf buffer size 1 MB : 122 
readCount : 268435456 raf buffer size 2 MB : 133 
readCount : 268435456 raf buffer size 4 MB : 29 
readCount : 268435456 raf buffer size 8 MB : 35 
readCount : 268435456 raf buffer size 16 MB : 38 
readCount : 268435456 raf buffer size 32 MB : 124 
readCount : 268435456 raf buffer size 64 MB : 241 
readCount : 268435456 raf buffer size 128 MB : 456 
readCount : 268435456 raf buffer size 256 MB : 1086 
readCount : 268435456 raf buffer size 512 MB : 2458 
readCount : 268435456 raf buffer size 1024 MB : 4952 

Фиксированный тест-buffSize:

@Test 
public void testBuffSizeReadPerformance2() throws Exception { 
    System.out.println(ManagementFactory.getRuntimeMXBean().getName()); 

    for (int i = 0; i < 10; i++) { 
     bufferSizePerformanceTest(1024 * 1024 * 1024); 
    } 
} 

Выход

[email protected] 
readCount : 268435456 raf buffer size 1024 MB : 127 
readCount : 268435456 raf buffer size 1024 MB : 111 
readCount : 268435456 raf buffer size 1024 MB : 20 
readCount : 268435456 raf buffer size 1024 MB : 17 
readCount : 268435456 raf buffer size 1024 MB : 23 
readCount : 268435456 raf buffer size 1024 MB : 19 
readCount : 268435456 raf buffer size 1024 MB : 21 
readCount : 268435456 raf buffer size 1024 MB : 22 
readCount : 268435456 raf buffer size 1024 MB : 20 
readCount : 268435456 raf buffer size 1024 MB : 33 

Как показывает тесты 2, время, затраченное на чтение с тем же buffSize (1024MB) довольно сильно отличается в 2-х тестов. Тест с фиксированным buffSize намного быстрее, чем тест вариации.

Мой вопрос: 1. Как это произошло, почему это будет быстрее? 2. Занимает ли MappedByteBuffer физическую память? Как я вижу в ActivityMonitor, он не будет занимать физическую память.

Благодаря

----- ----- Обновление

Буфер релиз код:

public static void releaseByteBuffer(ByteBuffer buffer) throws NoSuchFieldException, IllegalAccessException { 
    Cleaner cleaner = ((DirectBuffer) buffer).cleaner(); 
    cleaner.clean(); 
} 

Я не думаю, что причиной этой проблемы является использование памяти. Потому что он имеет тот же результат, даже если я включаю код выпуска и код gc. В любом случае, если речь идет об использовании памяти, я устанавливаю время цикла 100 во втором тесте, он должен использовать больше памяти, чем первый тест, но быстрее, чем первый.

----- Update 2 -----

Если я повернуть buffSize уменьшить вместо увеличения в тесте 1, проблема исчезнет.

@Test 
public void testBuffSizeReadPerformance3() throws Exception { 
    System.out.println(ManagementFactory.getRuntimeMXBean().getName()); 
    for (int i = getM(1024); i >= 0; i--) { 
     bufferSizePerformanceTest((int) (Math.pow(2, i) * 1024 * 1024)); 
    } 
} 

Выход:

[email protected] 
readCount : 268435456 raf buffer size 1024 MB : 101 
readCount : 268435456 raf buffer size 512 MB : 187 
readCount : 268435456 raf buffer size 256 MB : 31 
readCount : 268435456 raf buffer size 128 MB : 30 
readCount : 268435456 raf buffer size 64 MB : 36 
readCount : 268435456 raf buffer size 32 MB : 37 
readCount : 268435456 raf buffer size 16 MB : 37 
readCount : 268435456 raf buffer size 8 MB : 32 
readCount : 268435456 raf buffer size 4 MB : 44 
readCount : 268435456 raf buffer size 2 MB : 34 
readCount : 268435456 raf buffer size 1 MB : 55 

ответ

1

Вы не «изменения размера карты continuously'.You продолжать создавать новые карты, и не существует никакого механизма, посредством отображения высвобождаются, включая GC, поэтому вы используете все больше и больше памяти.

Вы должны стремиться использовать как можно меньше MappedByteBuffers, что может означать, что вам нужно также увеличить размеры.

Я не знаю, что делает ByteBufferUtil.releaseByteBuffer(buffer), или откуда оно происходит, но эти вещи их характера не могут быть надежными.

+0

Спасибо @EJP, см. Мое обновление. – Alexis

+0

Я бы сказал, что я не понимаю цели вашего тестового кода, но если вы не измените размер карты, вы, вероятно, всегда получаете одну и ту же базовую сопоставленную память, а не другой кусок, который сохраняет виртуальную память. Я не знаю, в чем цель его изменения. – EJP

+0

Я хочу найти, что некоторые факторы влияют на эффективность чтения файла при использовании другого размера карты, поэтому я пишу этот код. И я хочу знать, прочитал ли я файл в 1 ГБ, какой размер карты я должен использовать. – Alexis