为什么 Files.deleteIfExists 对于大文件需要这么长时间?

Why does Files.deleteIfExists take so long for large files?

在大文件上(此处35GB):

Files.deleteIfExists(Path.get("large.csv"));

使用 java 删除需要 >60 秒。稍后在控制台上用 rm large.csv 删除。

为什么?我可以加快从 java 中删除大文件的速度吗?

我会把这归咎于操作系统。在 Windows 和 Linux 上,Java 只需调用 OS 提供的 C 本机运行时库提供的方法来删除文件。

(查看OpenJDK源代码。)


那么为什么操作系统删除大文件需要很长时间?

  • 典型的文件系统会保留空闲磁盘块与使用中磁盘块的映射。如果您正在释放一个非常大的文件,则会释放大量块,因此需要更新空闲映射中的大量位并将其写入磁盘。

  • 典型的文件系统使用基于树的索引结构将文件偏移量映射到磁盘块。如果文件足够大,索引结构可能跨越多个磁盘块。删除文件时,需要扫描整个索引以找出包含需要释放的数据的所有块。

  • 如果文件碎片严重,索引块和空闲映射块分布广泛,这些成本会被放大。

  • 删除文件通常是同步完成的。至少,所有磁盘块在系统调用 returns 之前都被标记为空闲。 (如果不这样做,用户可能会抱怨删除文件​​不起作用。)

简而言之,当您删除一个巨大的文件时,有很多"disk" I/O 要做。操作系统这样做,而不是 Java.


那么为什么从命令行删除文件会更快?

一个可能的原因是,也许您使用的 rm 命令实际上只是将已删除的文件移动到回收站文件夹。那实际上是一个rename操作,比真正的delete快多了。

注意:这不是 rm 在 Linux 上的正常行为。

另一个可能的原因(在 Linux 上)是您要删除的文件的索引和空闲映射块在一个测试场景中位于缓冲区缓存中,而不是在另一个测试场景中。 (如果你的机器丢失了备用RAM,Linux OS会在RAM中缓存磁盘块以提高性能。效果很好。)