最近、私はJava MappedByteBufferに関するいくつかのテストを行った。私は、同じファイルを連続的にマップして読み込むと、読み込み時間が長くて長くかかることが分かりました。しかし、私が地図のサイズを変更しなかった場合、私は地図のサイズの変化のテストで同じマップのサイズを使用するよりも速くなります。マップサイズを連続的に変更するとJava MappedByteBufferのパフォーマンスが悪化して悪化する
私は、整数で満たされた1GBのファイル "dataFile"を持っています。
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));
}
}
バリエーション出力する読み出し約方法:
[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
、同じBUFFSIZE(1024メガバイト)と読み取りに費やされた時間は、2回の試験ではかなり異なっています。 fixed buffSizeを使用したテストは、バリエーションテストよりもはるかに高速です。
私の質問は: 1.これはどうして起こったのです、なぜ速くなるのでしょうか? 2. MappedByteBufferは物理メモリを占有していますか? ActivityMonitorに表示されるように、物理メモリを占有しません。
おかげ
-----更新-----
リリースバッファコード:
public static void releaseByteBuffer(ByteBuffer buffer) throws NoSuchFieldException, IllegalAccessException {
Cleaner cleaner = ((DirectBuffer) buffer).cleaner();
cleaner.clean();
}
私は、この問題の原因はメモリ使用量ではないと思います。それはリリースコードとgcコードをオンにしても同じ出力を持っているからです。とにかく、メモリ使用量については、2回目のテストでループ時間を100に設定し、最初のテストよりも多くのメモリを使用する必要がありますが、最初のテストよりも高速です。
-----アップデート2 -----
私が代わりにテスト1の増加により減少しBUFFSIZEを有効にした場合、問題が消えます。
@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
ありがとう@EJP、私の更新を参照してください。 – Alexis
私はあなたのテストコードの目的を理解していないと述べなければならないでしょうが、マップサイズを変更しないと、仮想メモリを節約する別のチャンクではなく、とにかくそれを変える目的がどういうものか分かりません。 – EJP
異なるマップサイズを使用しているときにファイルを読み込む効率にいくつかの影響があることを知りたいので、このコードを記述します。そして私は、1GBのファイルを読み込むかどうか、どのマップサイズを使うべきかを知りたい。 – Alexis