87

我注意到在 Windows 上执行文件(.exe 或 .dll)时,它被锁定并且无法删除、移动或修改。

另一方面,Linux 不会锁定正在执行的文件,您可以删除、移动或修改它们。

为什么 Windows 会锁定而 Linux 不锁定?锁定有优势吗?

4

8 回答 8

109

Linux 有一个引用计数机制,所以你可以在文件执行时删除它,只要某个进程(之前打开它的)有一个打开的句柄,它就会继续存在。当您删除该文件时,该文件的目录条目将被删除,因此无法再打开它,但已经使用该文件的进程仍然可以使用它。一旦使用该文件的所有进程终止,该文件将被自动删除。

Windows 没有此功能,因此它被迫锁定文件,直到从它执行的所有进程都完成。

我相信 Linux 的行为更可取。可能有一些深层的架构原因,但我发现最引人注目的主要(也是简单)原因是,在 Windows 中,您有时无法删除文件,您不知道为什么,而您所知道的只是某些进程将其保留在利用。在 Linux 中它永远不会发生。

于 2008-10-13T07:18:01.657 回答
31

据我所知,linux在运行时确实会锁定可执行文件——但是,它会锁定inode。这意味着您可以删除“文件”,但 inode 仍然在文件系统上,未受影响,您真正删除的只是一个链接。

Unix 程序一直使用这种思考文件系统的方式,创建一个临时文件,打开它,删除名称。您的文件仍然存在,但名称已释放供其他人使用,其他人无法看到它。

于 2008-10-13T07:19:06.847 回答
27

Linux确实锁定了文件。如果您尝试覆盖正在执行的文件,您将收到“ETXTBUSY”(文本文件忙)。但是,您可以删除该文件,并且内核将在删除最后一次对该文件的引用时删除该文件。(如果机器没有完全关闭,这些文件是检查文件系统时“Deleted inode has zero d-time”消息的原因,它们没有被完全删除,因为正在运行的进程有对它们的引用,现在他们是。)

这有一些主要优点,您可以升级正在运行的进程,方法是删除可执行文件,替换它,然后重新启动进程。甚至 init 也可以像这样升级,替换可执行文件,并向它发送信号,它会自己重新执行(),而无需重新启动。(这通常由您的包管理系统自动完成,作为升级的一部分)

在 Windows 下,替换正在使用的文件似乎很麻烦,通常需要重新启动以确保没有进程正在运行。

可能会有一些问题,例如,如果您有一个非常大的日志文件,并且您将其删除,但忘记告诉正在记录到该文件的进程重新打开该文件,它将保留引用,您会想知道为什么您的磁盘没有突然获得更多可用空间。

你也可以在 linux 下使用这个技巧来处理临时文件。打开文件,将其删除,然后继续使用该文件。当您的进程退出时(无论出于何种原因 - 甚至断电),该文件都将被删除。

lsof 和 fuser 之类的程序(或者只是在 /proc//fd 中查看)可以显示哪些进程打开了不再有名称的文件。

于 2008-12-30T10:51:39.140 回答
6

我认为你对 Windows 太绝对了。通常,它不会为可执行文件的代码部分分配交换空间。相反,它会锁定可执行文件和 DLL。如果再次需要丢弃的代码页,只需重新加载它们。但是使用 /SWAPRUN,这些页面被保存在交换中。这用于 CD 或网络驱动器上的可执行文件。因此,windows 不需要锁定这些文件。

对于 .NET,请查看Shadow Copy

于 2008-10-13T09:46:20.840 回答
6

我认为 linux / unix 不使用相同的锁定机制,因为它们是作为多用户系统从头开始构建的——这可能会导致多个用户使用同一个文件,甚至可能出于不同的目的。

锁定有优势吗?好吧,它可能会减少操作系统必须管理的指针数量,但现在节省的数量几乎可以忽略不计。我能想到的锁定的最大优势是:您可以节省一些用户可见的歧义。如果用户 a 正在运行一个二进制文件,而用户 b 将其删除,则实际文件必须保留,直到用户 A 的进程完成。然而,如果用户 B 或任何其他用户在文件系统上查找它,他们将无法找到它 - 但它会继续占用空间。对我来说并不是一个大问题。

我认为在很大程度上这更多是关于与窗口文件系统的向后兼容性的问题。

于 2008-10-13T07:14:24.860 回答
2

是否应该锁定文件中执行的代码是设计决定,MS 只是决定锁定,因为它在实践中具有明显的优势:这样您就不需要知道哪个应用程序使用哪个版本的哪个代码。这是 Linux 默认行为的一个主要问题,大多数人都忽略了这一点。如果系统范围的库被替换,您将无法轻易知道哪些应用程序使用此类库的代码,大多数情况下您能得到的最好的结果是包管理器知道这些库的一些用户并重新启动它们。但这仅适用于一般且众所周知的事物,例如 Postgres 及其库等。更有趣的场景是,如果您针对某些 3rd 方库开发自己的应用程序并且这些库被替换,因为大多数时候包管理器根本不知道您的应用程序。然后' s 不仅是本机 C 代码等的问题,它几乎可以发生在任何事情上:只需使用带有 mod_perl 的 httpd 和使用包管理器安装的一些 Perl 库,然后让包管理器出于任何原因更新这些 Perl 库。它不会重新启动您的 httpd,只是因为它不知道依赖项。有很多这样的例子,仅仅是因为任何文件都可能包含任何运行时在内存中使用的代码,想想 Java、Python 和所有这些东西。

所以有一个很好的理由认为默认锁定文件可能是一个不错的选择。不过,您无需同意这些理由。

那么MS做了什么?他们只是创建了一个 API,让调用应用程序有机会决定是否应该锁定文件,但他们决定此 API 的默认值是为第一个调用应用程序提供排他锁。查看有关CreateFile及其dwShareMode参数的 API 。这就是为什么您可能无法删除某些应用程序正在使用的文件的原因,它根本不关心您的用例,使用默认值,因此获得了 Windows 对文件的排他锁。

请不要相信有人告诉你一些关于 Windows 不使用 HANDLE 的引用计数或不支持硬链接等的事情,这是完全错误的。几乎每个使用 HANDLE 的 API 都记录了它关于引用计数的行为,您可以轻松地阅读几乎所有关于 NTFS 的文章,它确实支持硬链接并且一直支持。从 Windows Vista 开始,它也支持符号链接,并且通过提供 API 来读取给定文件的所有内容等,改进了对硬链接的支持。

此外,您可能只是想看看Ext4中用于描述文件的结构与NTFS中的结构相比,它们有很多共同点。两者都使用范围的概念,它将数据与文件名等属性分开,而索引节点几乎只是一个较旧但类似概念的另一个名称。甚至 Wikipedia 在其文章中也列出了这两种文件系统。

与网络上的其他操作系统相比,Windows 中的文件锁定确实有很多 FUD,就像碎片整理一样。只需在Wikipedia上阅读一些内容,就可以排除其中一些 FUD 。

于 2015-05-16T08:39:03.230 回答
0

NT 变体具有

打开文件

命令,它将显示哪些进程对哪些文件有句柄。但是,它确实需要启用系统全局标志“维护对象列表”

打开文件/本地/?

告诉您如何执行此操作,并且这样做会导致性能损失。

于 2008-10-13T09:11:16.340 回答
0

可执行文件在运行时逐渐映射到内存。这意味着可执行文件的某些部分根据需要加载。如果在映射所有部分之前换出文件,则可能会导致严重的不稳定。

于 2014-10-21T18:00:47.857 回答