2016-05-25 3 views
1

Kürzlich hatte ich einige Tests über Java MappedByteBuffer. Ich fand heraus, dass wenn ich kontinuierlich die gleiche Datei abdecke und lese, die Zeit, die ich damit verbringe, länger und länger zu lesen. Aber wenn ich die Kartengröße nicht ändere, wäre es schneller als das ich die gleiche Kartengröße im Map Size Variation Test verwende.Java MappedByteBuffer Leistung immer schlechter, wenn Sie die Kartengröße kontinuierlich ändern

Ich habe eine Datei "DataFile" in 1GB, die mit Ganzzahlen gefüllt.

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(); 
} 

und ein Verfahren darüber

// 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)); 
} 

Die Variation BUFFSIZE Test

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 Ausgänge Lesen:

[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 

Der feste BUFFSIZE Test:

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

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

Ausgabe

[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 

Wie die 2 Tests zeigen, die mit dem gleichen BUFFSIZE (1024MB) verbrachte Zeit beim Lesen ist in zwei Tests ganz anders. Der Test mit fester buffSize ist viel schneller als der Variationstest.

Meine Frage ist: 1. Wie ist das passiert, warum wird es schneller? 2. Besetzt der MappedByteBuffer physischen Speicher? Wie ich im ActivityMonitor sehe, wird es keinen physischen Speicher belegen.

Dank

----- ----- Update-

Der Freigabepuffercode:

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

Ich glaube nicht, dass die Ursache für dieses Problem Speichernutzung ist. Weil es die gleiche Ausgabe hat, selbst wenn ich den Freigabecode und den GC-Code einschalte. Wie auch immer, wenn es um die Speichernutzung geht, setze ich die Schleifenzeiten im zweiten Test auf 100, sollte mehr Speicher als der erste Test verbrauchen, aber es ist schneller als der erste.

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

Wenn ich die BUFFSIZE drehe 1 statt Erhöhung des Tests zu verringern, das Problem verschwinden.

@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)); 
    } 
} 

Ausgang:

[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 

Antwort

1

Sie nicht ‚ändern sich die Kartengröße continuously'.You neue Karten halten zu schaffen, und es gibt keinen Mechanismus, mit dem die Zuordnungen freigegeben werden, einschließlich GC, Sie verwenden also immer mehr Speicher.

Sie sollten versuchen, so wenig wie möglich MappedByteBuffers zu verwenden, was bedeuten kann, dass Sie die Größen auch größer machen müssen.

Ich weiß nicht, was ByteBufferUtil.releaseByteBuffer(buffer) der Fall ist, oder wo es herkommt, aber diese Dinge von ihrer Natur nach nicht zuverlässig sein.

+0

Dank @EJP, siehe mein Update. – Alexis

+0

Ich muß sagen, dass ich den Zweck Ihres Testcode nicht verstehen, aber wenn man Sie wahrscheinlich den gleichen zugrunde liegenden Bildspeicher immer eher als ein anderen Brocken immer sind nicht die Kartengröße ändern, die virtuellen Speicher speichert. Ich weiß nicht, welchen Zweck es hätte, es zu ändern. – EJP

+0

ich finden will, ist es etwas auf die Effizienz des Lesens einer Datei beeinflussen, wenn verschiedene Kartengröße verwenden, so schreibe ich diesen Code. Und ich möchte wissen, ob ich eine Datei in 1 GB lesen, welche Kartengröße ich verwenden soll. – Alexis

Verwandte Themen