下边我列出以下各个大小文件,各种读取方式所花费的时间,仅作参考。
表格里边我会用Buffer作为BufferedReader的简写,Random作为RandomAccessFile的简写,FileInput作为FileInputStream的简写,Map作为内存直接映射的简写。我给出两次测试结果。
146M文件
第一次测试
第二次测试
Buffer
4.737s
4.581s
Random
0.251s
0.249s
FileInput
0.27s
0.269s
Map
0.102s
0.104s
除了BufferedReader之外,其他的读取时间基本上没有太大区别。
356M文件
第一次测试
第二次测试
Buffer
10.889s
10.71s
Random
0.558s
0.589s
FileInput
0.637s
0.635s
Map
0.125s
0.124s
570M文件
第一次测试
第二次测试
Buffer
17.215s
17.393s
Random
2.756s
2.243s
FileInput
1.924s
1.975s
Map
0.203s
0.197s
712M文件
第一次测试
第二次测试
Buffer
21.852s
23.262s
Random
3.481s
3.529s
FileInput
3.829s
3.42s
Map
0.246s
0.258s
998M文件
第一次测试
第二次测试
Buffer
34.08s
32.437s
Random
21.817s
20.589s
FileInput
9.669s
9.792s
Map
15.481s
16.886s
由以上图表可以看出,在文件大小一般的情况下,随着文件大小的增加,内存映射基本保持在1秒以下,基本0.2s左右,而其他的都会随着文件的增大有明显的变化,这就是内存直接映射秒杀的地方,但是就是文件增加到了998M之后,时间突然之间会增加很大,不知道是不是因为文件太大,以致于内存里边需要执行操作系统提供的一些保护算法而浪费时间了,这个有待考证,也可能是每次运行完之后没有清理内存,导致数据堵塞,因为内存映射方式,Java没有提供相应的直接回收MappedByteBuffer区域的方法,这也会导致另外一种异常就是内存不够。
然后我在网上搜了两种解决方式,但是我自己也没有实验出来,代码是执行了,但是不知道从哪里看出他执行前后的区别。这里也把代码放上。
第一种方式:
System.gc();
System.runFinalization();
try {
Thread.sleep(3000);
} catch (InterruptedException e) {
e.printStackTrace();
}
第二种方式:
public static void unmap(final MappedByteBuffer buffer) {
if (buffer == null) {
return;
}
AccessController.doPrivileged(new PrivilegedAction<Object>() {
public Object run() {
try {
Method getCleanerMethod = buffer.getClass().getMethod("cleaner", new Class[0]);
if (getCleanerMethod != null) {
getCleanerMethod.setAccessible(true);
Object cleaner = getCleanerMethod.invoke(buffer, new Object[0]);
Method cleanMethod = cleaner.getClass().getMethod("clean", new Class[0]);
if (cleanMethod != null) {
cleanMethod.invoke(cleaner, new Object[0]);
}
}
} catch (Exception e) {
e.printStackTrace();
}
return null;
}
});
}
但是执行这个之后,会把时间拖慢,也是一个问题,所以这个问题待解决。
上边是我测试了几个方式的读取方式,这样以后实验室的使用读取文件的方式的时候,可以选用最适合的方式,如果时间是最紧要的,那么可以选用内存直接映射,但是这个要保证内存够用,而且文件合适的情况下,至于上边的那个问题,下边我会继续关注,如果谁了解了,欢迎提示~