java - 是什么使得在没有缓冲区的情况下读取文件如此昂贵?

标签 java performance io inputstream

最近,我创建了一个界面,强制用户实现单个 fromStream(OutputStream)其默认方法如下所示:

public default T fromFile(File file) throws IOException {
    try (InputStream stream = new FileInputStream(file)) {
        return fromStream(stream);
    }
}

很快就发现,由于直接从 FileInputStream 读取单个字节,这是非常昂贵的(每 MB 几秒)。 .

将其包装在 BufferedInputStream 中解决了我的问题,但它给我留下了一个问题:为什么 FileInputStream太贵了。

读取字节时文件 channel 不会关闭或打开,那么为什么首先需要缓冲区呢?

最佳答案

如果使用 read() 方法从无缓冲流中读取字节,JVM 最终将向操作系统重复执行读取系统调用以从文件中读取单个字节。 (在幕后,JVM 可能正在调用 read(addr, offset, count),计数为 1。)

进行系统调用的成本很大。至少比常规方法调用高几个数量级。这是因为以下方面存在大量开销:

  • 在应用程序(非特权)安全域和系统(特权)安全域之间切换上下文。需要保存寄存器集、需要更改虚拟内存映射、需要刷新 TLB 条目等。
  • 操作系统必须做各种额外的事情来确保系统调用所请求的内容是合法的。在这种情况下,操作系统必须在给定当前文件位置和大小的情况下确定请求的偏移量和计数是否正确,该地址是否在应用程序的地址空间内,并将其映射为可写。等等。

相比之下,如果您使用缓冲流,该流将尝试从操作系统中大块读取文件。这通常会导致系统调用数量减少数千倍。

<小时/>

事实上,这与文件如何存储在磁盘上无关。确实,数据最终必须一次读取一个 block ,等等。但是,操作系统足够智能,可以进行自己的缓冲。它甚至可以预读文件的部分内容,以便当系统调用读取它们时,它们位于(内核)内存中,为应用程序做好准备。

多次单字节 read() 调用极不可能导致额外的磁盘流量。唯一可能出现这种情况的情况是,如果您在每个 read() 之间等待很长时间...并且操作系统重用了缓存磁盘 block 的空间。

关于java - 是什么使得在没有缓冲区的情况下读取文件如此昂贵?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/42035407/

相关文章:

c - 使用scanf在c中的单行上输入多个 double 和不使用数组的循环

javascript - Angular Js 应用程序中的内存问题

python - AWS Lambda 和 Python 的 .pyc 文件

mysql - 如何使用 group by、where 和 order by 子句在大表(>38.700.000 行)上定义索引

Java自动设置按钮名称

linux - IO 阻塞进程是否会在 'top' 输出中显示 100% 的 CPU 使用率?

haskell - 我使用 randomRIO 错了吗?

java - 解决这个问题的方法?

java - linux上的tcp java连接速率限制

java - Java getResource 方法仅适用于特定扩展吗?