FileInputStream 真的是无缓冲的吗?

Is FileInputStream Really Unbuffered?

FileInputStream 使用 this 本机方法读取用户提供的缓冲区中的字节。正如我们在实现中看到的那样,user-space 缓冲区确实分配了长度 max(BUF_SIZE, supplied buffer length)。然后将该缓冲区传递给 IO_Read。我无法提取此方法的实现,但我很确定这是标准的 C 缓冲读取。为什么 FileInputStream 然后说是无缓冲的? BufferedReader 使用了什么额外的缓冲?

编辑:Benchmark比较 100M 文件的读取时间及其结果:

Benchmark                         Mode  Cnt      Score      Error  Units
StreamIOBenchmark.bisMultiBytes   avgt   30     27.640 ±    1.117  ms/op
StreamIOBenchmark.bisSingleBytes  avgt   30    400.552 ±   26.921  ms/op
StreamIOBenchmark.fisMultiBytes   avgt   30     25.231 ±    1.459  ms/op
StreamIOBenchmark.fisSingleBytes  avgt   30  97991.213 ± 5620.685  ms/op

真正的区别在于读取单个字节时,因为 FIS 将为每个字节进行新的系统调用。然而,当一次读取 8k 字节时,FIS (fisMultiBytes) 和 BIS (bisMultiBytes) 的表现非常相似。

Is FileInputStream really unbuffered?

是的。真的。

I could not pull up the implementation of this method but I am pretty sure this is the standard C buffered reading.

不,不是。本机代码未使用 C 缓冲 I/O。它正在对临时缓冲区执行 read(2) 调用。然后它将数据从临时缓冲区复制到调用者提供的 byte[].

在我正在查看的 Java 11u 代码中,临时缓冲区要么是一个小的 on-stack 缓冲区,要么是一个更大的 mallocfreenative 通话期间。

OpenJDK Java 11u 代码库中的相对路径名是 ./src/java.base/share/native/libjava/io_util.c。寻找 readBytes 方法。 (这是通过 ./src/java.base/share/native/libjava/FileInputStream.c 中的本机入口点方法调用的)

io_utils.c 中的 IO_Read 是一个别名 handleRead 的宏,它包装了 read(2) 调用。

更新

我刚刚注意到您已经找到 link 到 io_util.c 的 Java 8u 版本。它的行为方式与我上面描述的 11u 代码相同。所以也许你只是误读了你找到的 C 代码?


Why is FileInputStream then said to be unbuffered?

它“据说”是无缓冲的,因为它确实是无缓冲的

And what additional buffering is BufferedReader using?

您可以通过查看 BufferedReader 的 (Java) 源代码来了解这一点。


提示:与其对 JVM 本机代码实现的工作方式做出(错误的)假设,不如下载并阅读 OpenJDK 源代码。任何有足够磁盘 space (1.2GB) 的人都可以下载。