最近我对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));
}
}
变体输出:
14071@LiuzhMacbook.local
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);
}
}
输出
14157@LiuzhMacbook.local
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个测试所示,在2次测试中,使用相同buffSize(1024MB)读取的时间差别很大。使用固定buffSize的测试比变化测试快得多。
我的问题是: 1.这是怎么发生的,为什么会更快? 2. MappedByteBuffer是否占用物理内存?正如我在ActivityMonitor中看到的那样,它不会占用物理内存。
由于
-----更新-----
发布缓冲区代码:
public static void releaseByteBuffer(ByteBuffer buffer) throws NoSuchFieldException, IllegalAccessException {
Cleaner cleaner = ((DirectBuffer) buffer).cleaner();
cleaner.clean();
}
我不认为这个问题的原因是内存使用情况。因为即使我打开发布代码和gc代码它也有相同的输出。无论如何,如果是关于内存使用,我在第二次测试中将循环次数设置为100,它应该使用比第一次测试更多的内存,但它比第一次测试更快。
-----更新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));
}
}
输出:
16651@LiuzhMacbook.local
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
答案 0 :(得分:1)
你不是'不断改变地图大小'。你一直在创建新的地图,并且没有发布映射的机制,包括GC,所以你正在使用越来越多的内存
您应该尽可能少地使用MappedByteBuffers
,这可能意味着您需要将尺寸设置得更大。
我不知道ByteBufferUtil.releaseByteBuffer(buffer)
做了什么,或者它来自哪里,但这些性质的东西不可靠。