为什么FileOutputStream不会抛出OutOfMemoryException

时间:2010-07-17 21:28:37

标签: java io buffer

我在Windows(64位)和Linux(32位)上尝试过以下代码。

我确信没有BufferedOutputStream,代码必然会抛出OutOfMemoryException,但却没有。

为什么?谁在那里做{caching / buffer / steaming}到磁盘?

如果与答案相关,请说明完整的流程(Java API - >系统调用)?

此代码是否使用NIO?

/我很困惑。

import java.io.DataOutputStream;
import java.io.FileOutputStream;
import java.io.IOException;

public class WriteHugeFileToDisk {
    private static int BYTE = 1;
    private static int KILBYTE = BYTE * 1024;
    private static int MEGABYTE = KILBYTE * 1024;
    private static int GIGABYTE = MEGABYTE * 1024;
    private static long TERABYTE = GIGABYTE * 1024L;

    public static void main(String[] args) throws IOException {
        FileOutputStream fileOutputStream = new FileOutputStream(args[0]);
        DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);

        byte[] buffer = new byte[MEGABYTE];
        for(int i = 0; i < buffer.length; i++) {
            buffer[i] = (byte)i;
        }

        for(long l = 0; l < 4000; l++) {
            dataOutputStream.write(buffer);
            ;
        }

    }
}

我使用Java 6运行此代码。使用以下调用:

视窗:

java WriteHugeFileToDisk %TEMP%\hi.txt

Linux的:

java WriteHugeFileToDisk /mnt/hi.info

请注意:代码会创建4GB文件,仅供测试。

4 个答案:

答案 0 :(得分:5)

为什么会抛出OutOfMemoryException?它只是写入磁盘。如果FileOutputStreamDataOutputStream 某些缓存(我还没有检查过),我不会感到惊讶,但他们当然不需要缓冲所有内容

这段代码并没有直接使用NIO,虽然我不会感到惊讶,如果有一些内部的东西。至于涉及什么系统调用以及什么时候 - 这将是特定于实现的,但重要的是要意识到DataOutputStreamFileOutputStream都不是为了缓冲一切。您向它们写入一些数据,其中一些数据可能会写入磁盘。如果您刷新或关闭流,那么应该使 all 到目前为止所写的数据到达磁盘。如果你刷新或关闭流,我希望只有一个相当小的数量(再次,特定于实现)被缓存,如果有的话。

请注意,BufferedOutputStream 确实引入了缓存 - 但只是您要求的(或默认值)。同样,它不会缓冲所有,除非你要求的数据量与写入时一样多。

答案 1 :(得分:1)

缓冲流是一个流包装器,它(很明显地)将数据缓冲到内存中,然后再将其传递给底层流。当与文件流结合使用时,这可以提供更好的性能,因为读取或写入硬盘驱动器会涉及很多开销。缓冲允许您通过将低效的多次读取或写入折叠成单个,有效,更大的读取/写入来显着减少读取/写入次数。但是,对于应用程序的良好运行,至关重要。它只是帮助您减少对物理设备的访问。

与其他语言相比,Java无法更直接地访问您的计算机设备。在您的程序和硬盘上的位之间,仍然有几个层有权缓冲或缓存Java拼命试图从磁盘上获取的内容。据我所知,操作系统可以(通常会)缓存或缓冲内容,而某些硬件也会这样做。

在操作的Java意义上,缓冲与设备读取或写入的成功或失败无关,或与此相关,与任何流无关。

答案 2 :(得分:1)

这两条指令几乎不占用内存并打开文件句柄。

FileOutputStream fileOutputStream = new FileOutputStream(args[0]);
DataOutputStream dataOutputStream = new DataOutputStream(fileOutputStream);

分配并填充1MB数据,该字节数组存储在内存中。

byte[] buffer = new byte[MEGABYTE];
for(int i = 0; i < buffer.length; i++) {
    buffer[i] = (byte)i;
}

将此1MB数据写入输出文件4000倍。

for(long l = 0; l < 4000; l++) {
    dataOutputStream.write(buffer);
}

结论:消耗1MB内存并将4GB数据写入文件。因此,除非你的内存很少,否则不能抛出OutOfMemoryException

答案 3 :(得分:1)

  

谁在那里对磁盘进行{缓存/缓冲/蒸制}?

没有人。它直接写入磁盘。无任何增量内存使用。