我的例子是《我的世界》。在 Linux 上运行 Bukkit 时,我可以删除或更新 /plugins 文件夹中的 .jar 文件,然后只需运行“reload”命令即可。
在 Windows 中,我必须关闭整个服务器进程,因为当我尝试删除或替换 .jar 文件时,它会抱怨该文件当前正在使用中。
这对我来说太棒了,但为什么会发生这种情况呢? Linux 在这里做了什么不同的事情?
答案1
Linux 删除文件的方式与 Windows 完全不同。首先,简要解释一下 *unix 本机文件系统中如何管理文件。
文件以称为 的多级结构保存在磁盘上i-node
。每个 i 节点在单个文件系统上都有一个唯一的编号。 i 节点结构保留有关文件的不同信息,例如文件大小、为文件分配的数据块等,但为了回答这个问题,最重要的数据元素是link counter
.这些directories
是保存有关文件的记录的文件。每条记录都有它所引用的 i 节点号、文件名长度和文件名本身。这一方案允许人们拥有“指针”,即“链接”到位于不同位置、具有不同名称的同一文件。 i 节点的链接计数器实际上保存引用该 i 节点的链接数量。
当某个进程打开文件时会发生什么?首先该open()
函数搜索文件记录。然后它检查该 i 节点的内存中 i 节点结构是否已存在。如果某些应用程序已打开此文件,则可能会发生这种情况。否则,系统初始化一个新的内存 i 节点结构。然后系统增加内存中i节点结构的打开计数器并将其文件描述符返回给应用程序。
用于删除文件的 Linux 库调用称为unlink
.该函数从目录中删除文件记录并减少 i 节点的链接计数器。如果系统发现内存中存在 i 节点结构并且其打开计数器不为零,则此调用将控制权返回给应用程序。否则,它检查链接计数器是否变为零,如果变为零,则系统释放为 i 节点和 i 节点本身分配的所有块并返回到应用程序。
应用程序关闭文件会发生什么?该函数close()
递减打开计数器并检查其值。如果该值非零,则函数返回到应用程序。否则,它检查 i 节点链接计数器是否为零。如果它为零,则在返回到应用程序之前释放文件的所有块和 i 节点。
此机制允许您在打开文件时“删除”文件。同时,打开文件的应用程序仍然可以访问文件中的数据。因此,在您的示例中,JRE 仍然保持其文件版本打开,而磁盘上还有另一个更新版本。
此外,此功能允许您更新系统中的 glibc(libc)(所有应用程序的核心库),而不会中断其正常运行。
视窗
20 年前,我们在 DOS 下不知道除了 FAT 之外还有任何其他文件系统。这种文件系统有不同的结构和管理原则。这些原则不允许您在打开文件时将其删除,因此 DOS 和最近的 Windows 必须拒绝对打开的文件的任何删除请求。 NTFS 可能允许与 *nix 文件系统相同的行为,但 Microsoft 决定保留文件删除的习惯行为。
这就是答案。不短,但现在你有了想法。
编辑Win32
:关于混乱来源的好读物:https://web.archive.org/web/20190218083407/https://blogs.msdn.microsoft.com/oldnewthing/20040607-00/?p=38993
感谢@Jon