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 缓冲区,要么是一个更大的 malloc
和 free
在 native
通话期间。
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) 的人都可以下载。
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 缓冲区,要么是一个更大的 malloc
和 free
在 native
通话期间。
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) 的人都可以下载。