Java 为什么FileOutputStream不抛出OutOfMemoryException
我在Windows(64位)和Linux(32位)上都试过下面的代码 我确信,如果没有BufferedOutputStream,代码一定会抛出OfMemoryException,但事实并非如此 为什么呢?谁在那里对磁盘进行{caching/buffer/steaming} 如果与答案相关,您能否描述完整的流程(JavaAPI->系统调用) 这段代码使用NIO吗 /我很困惑Java 为什么FileOutputStream不抛出OutOfMemoryException,java,io,buffer,Java,Io,Buffer,我在Windows(64位)和Linux(32位)上都试过下面的代码 我确信,如果没有BufferedOutputStream,代码一定会抛出OfMemoryException,但事实并非如此 为什么呢?谁在那里对磁盘进行{caching/buffer/steaming} 如果与答案相关,您能否描述完整的流程(JavaAPI->系统调用) 这段代码使用NIO吗 /我很困惑 import java.io.DataOutputStream; import java.io.FileOutputStre
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);
;
}
}
}
Linux:
java WriteHugeFileToDisk /mnt/hi.info
请注意:代码只为测试创建了一个4GB的文件,文件中包含了大量的数据。为什么它会抛出一个
OutOfMemoryException
?它只是在写磁盘。如果FileOutputStream
和DataOutputStream
有一些缓冲(我没有检查),我不会感到惊讶,但它们肯定不需要缓冲您编写的所有内容
这段代码没有直接使用NIO,尽管如果一些内部内容使用了NIO,我也不会感到惊讶。至于涉及到什么系统调用以及何时-这将是特定于实现的,但重要的是要认识到,无论是DataOutputStream
还是FileOutputStream
都不能缓冲所有内容。您向它们写入一些数据,其中一些数据可能会写入磁盘。如果刷新或关闭流,则应使迄今为止写入的所有数据都进入磁盘。如果您不刷新或关闭流,我希望只缓存一小部分(同样是特定于实现的),如果有的话
请注意,
BufferedOutputStream
确实引入了缓存,但只满足您的要求(或默认设置)。同样,它不会缓冲所有内容,除非您要求的缓冲区与您在数据方面写入的缓冲区一样多。缓冲流是一个流包装器,它(很明显)在将数据传递到底层流之前将数据缓冲到内存中。当与文件流结合使用时,这会提供更好的性能,因为读取或写入硬盘驱动器会带来大量开销。通过将原本效率低下的多个读写操作折叠为一个高效、更大的读写操作,缓冲允许您显著减少读写次数。但是,它对应用程序的良好运行不是至关重要的。它只是帮助您减少对物理设备的访问
Java没有比其他语言更直接地访问计算机的设备。在您的程序和硬盘上的位之间,仍然有几个层有权缓冲或缓存Java拼命从磁盘获取的内容。据我所知,操作系统可以(而且通常会)缓存或缓冲东西,一些硬件也会这样做
在Java操作的意义上,缓冲与对设备或任何流的读写的成功或失败无关。这两条指令几乎不消耗内存并打开文件句柄
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;
}
byte[]buffer=新字节[MB];
for(int i=0;i
将此1MB数据写入输出文件4000次
for(long l = 0; l < 4000; l++) {
dataOutputStream.write(buffer);
}
for(长l=0;l<4000;l++){
dataOutputStream.write(缓冲区);
}
结论:消耗1MB内存,将4GB数据写入文件。因此,除非您的内存非常少,否则无法抛出OutOfMemoryException
谁在那里对磁盘进行{caching/buffer/steaming}
没有人。它直接写入磁盘。没有任何增量内存使用。回答得好,我只想补充一点,缓冲的关键是性能。如果您写入的每个字节最终都是磁盘写入操作,那么速度会很慢。如果在磁盘上缓冲相当于一个块的数据,这将是一个巨大的改进。如果你开始缓冲千兆字节的数据,你就不会再看到每增加一兆字节的缓冲区大小有多大的改进了。@Mattias:True。当然,如果一个写调用已经在写一个兆字节,那么缓冲这些就没有什么意义了。
for(long l = 0; l < 4000; l++) {
dataOutputStream.write(buffer);
}