Java 写入文件到磁盘会经历哪些过程?
Java 写入文件到磁盘会经历哪些过程?
重点回答
这个问题虽然主要考察对操作系统缓存、文件系统和磁盘的理解,不过最好在开头再提一下 Java 中的操作,表现出从应用层到底层 DMA 的全方位理解。
第一步:写入文件缓冲区
为了提高效率,写入文件都会利用缓冲区,即当写入数据时,数据先被存储到缓冲区,而不是直接写入磁盘。缓冲区的目的是减少磁盘 IO 操作的次数,提高性能。
一般用的是 BufferedOutputStream 或 BufferedWriter 类。
第二步:write 系统调用(不是 Java 中的 write)
当缓冲区写满了,或者 Java 程序主动调用 flush() 或 close() 时,会触发相应的系统调用(write()),将数据从用户态传递到内核态。
操作系统接收到系统调用后,会将数据写入内核缓冲区(通常称为Page Cache)。这时,数据还在内存中,并未立即写入磁盘。
第三步:DMA 拷贝
操作系统中的 I/O 调度器决定实际的写入顺序,等到调度后,数据从内核缓冲区通过 DMA(Direct Memory Access)或中断机制传递到磁盘控制器的硬件缓冲区
第四步:写入磁盘
磁盘控制器最终将数据写入到磁盘的物理扇区中(磁盘上的数据写入可能涉及到旋转延迟、寻道时间等物理过程)。
如果 Java 文件写入想直接刷盘而不是先被写到页缓存中,可以执行 Java 提供了原子文件操作(FileChannel 的 force() 方法),确保写入的内容在物理磁盘上持久化,并且避免操作系统的缓存延迟。
扩展知识
什么是 DMA?
DMA(直接内存访问)是一种用于数据传输的技术,允许外设或外部设备(如硬盘、网络卡、显卡等)直接与系统内存进行交互,而不需要 CPU 的干预。这种方式可以极大地提高数据传输效率,减少 CPU 的负担,优化系统性能。
如果没有 DMA,CPU 会直接参与所有的内存到外设或外设到内存的数据传输。这不仅会占用 CPU 资源,还会导致数据传输速度较慢!
BufferedOutputStream 写入示例
1 | import java.io.BufferedOutputStream; |
文件系统的 fsync()、fdatasync() 调用
- fsync() 是一个系统调用,用于强制将一个文件描述符所对应的文件数据从 Page Cache 刷新到磁盘。与 flush() 不同,fsync() 会确保所有数据(不仅仅是文件内容,还有元数据如修改时间)都被写入磁盘。
- fdatasync() 类似于 fsync(),但是它只会同步文件的内容数据,不包括元数据。所以 fdatasync() 会比 fsync() 更高效一些。
Comments