我有一个关于Java序列化的问题。
我只是写了10个数组的大小int[] array = new int[2^28]到我的硬盘(我知道这有点大,但我需要这样)使用FileOutputStream和BufferedOutputStream与Dataoutputstream相结合。在每次序列化之前,我创建一个新的FileOutputstream和所有其他流,然后我关闭并刷新我的流。
问题:第一次序列化大约需要2秒,然后增加到17秒,并保持在这个级别。这里的问题是什么?如果我进入代码,我可以看到FileOutputStreams需要大量的时间用于writeByte(…)。这是由于硬盘缓存(满)?我怎样才能避免这种情况呢?我可以清除它吗?
下面是我的简单代码: public static void main(String[] args) throws IOException {
System.out.println("### Starting test");
for (int k = 0; k < 10; k++) {
System.out.println("### Run nr ... " + k);
// Creating the test array....
int[] testArray = new int[(int) Math.pow(2, 28)];
for (int i = 0; i < testArray.length; i++) {
if (i % 2 == 0) {
testArray[i] = i;
}
}
BufferedDataOutputStream dataOut = new BufferedDataOutputStream(
new FileOutputStream("e:\test" + k + "_" + 28 + ".dat"));
// Serializing...
long start = System.nanoTime();
dataOut.write(testArray);
System.out.println((System.nanoTime() - start) / 1000000000.0
+ " s");
dataOut.flush();
dataOut.close();
}
}
dataOut的地方。Write (int[], 0, end)
public void write(int[] i, int start, int len) throws IOException {
for (int ii = start; ii < start + len; ii += 1) {
if (count + 4 > buf.length) {
checkBuf(4);
}
buf[count++] = (byte) (i[ii] >>> 24);
buf[count++] = (byte) (i[ii] >>> 16);
buf[count++] = (byte) (i[ii] >>> 8);
buf[count++] = (byte) (i[ii]);
}
}
和' protected void checkBuf(int need)抛出IOException {
if (count + need > buf.length) {
out.write(buf, 0, count);
count = 0;
}
}`
BufferedDataOutputStream扩展了BufferedOutputStream随fits框架一起提供。它只是将BufferedOutputStream与DataOutputStream结合起来,以减少编写大数组时方法调用的数量(这使它更快……)。
输出如下:
基准开始开始运行0
2.001972271开始运行1
1.986544604开始运行2
15.663881232开始跑3
17.652161328开始跑4
18.020969301开始跑步5
11.647542466开始运行6
为什么时间增加这么多?
谢谢你,
Eeth
在这个程序中,我将1gb填充为int值,并"强制"将这些值写入磁盘。
String dir = args[0];
for (int i = 0; i < 24; i++) {
long start = System.nanoTime();
File tmp = new File(dir, "deleteme." + i);
tmp.deleteOnExit();
RandomAccessFile raf = new RandomAccessFile(tmp, "rw");
final MappedByteBuffer map = raf.getChannel().map(FileChannel.MapMode.READ_WRITE, 0, 1 << 30);
IntBuffer array = map.order(ByteOrder.nativeOrder()).asIntBuffer();
for (int n = 0; n < array.capacity(); n++)
array.put(n, n);
map.force();
((DirectBuffer) map).cleaner().clean();
raf.close();
long time = System.nanoTime() - start;
System.out.printf("Took %.1f seconds to write 1 GB%n", time / 1e9);
}
当每个文件被强制到磁盘时,它们每个占用的时间大约相同。
Took 7.7 seconds to write 1 GB
Took 7.5 seconds to write 1 GB
Took 7.7 seconds to write 1 GB
Took 7.9 seconds to write 1 GB
Took 7.6 seconds to write 1 GB
Took 7.7 seconds to write 1 GB
但是,如果我注释掉map.force();
,我将看到这个配置文件。
Took 0.8 seconds to write 1 GB
Took 1.0 seconds to write 1 GB
Took 4.9 seconds to write 1 GB
Took 7.2 seconds to write 1 GB
Took 7.0 seconds to write 1 GB
Took 7.2 seconds to write 1 GB
Took 7.2 seconds to write 1 GB
在它变慢之前,它将缓冲大约2.5 GB,大约是我主内存的10%。
您可以通过等待之前的写操作完成来清空缓存。
基本上你有1 GB的数据和磁盘的持续写入速度似乎是大约60 MB/s,这是合理的SATA硬盘驱动器。如果你得到比这更高的速度,那是因为数据并没有真正写入磁盘,实际上是在内存中。
如果你想让这个更快,你可以使用内存映射文件。这样做的好处是在后台写入磁盘,因为你正在填充"数组",也就是说,它可以完成写入几乎只要你完成设置的值。
另一个选择是得到一个更快的驱动器。单个250gb的SSD驱动器可以维持大约200mb/s的写速度。在RAID配置中使用多个驱动器还可以提高写速度。
第一次写操作可能只是填满了硬盘的缓存,而没有实际写入磁盘。