锁定执行文件:Windows锁定,Linux锁定。为什么?


82

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

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

为什么Windows在Linux不锁定时锁定?锁定有优势吗?


6
有一个名为WhoLockMe的实用程序,可将一个菜单项添加到资源管理器中的上下文菜单,该菜单项可以显示锁定给定文件的过程。当您收到奇怪的文件锁定错误时,此功能极为有用。编辑:我知道这不能回答问题,但是我认为在上下文中它足以保证单独回答(仅与评论相反)。
JesperE

Answers:


106

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

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

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


2
请注意,您可以使用Windows中的“进程资源管理器”之类的工具来查看正在使用文件/文件夹的进程。
J c

14
支持Linux行为的一个实际原因是,您可以在系统运行时更新操作系统和其他软件,并且永远不会/很少重启(您甚至可以不重启就切换正在运行的内核,这很困难,只能将其称为适用于对正常运行时间至关重要的应用)。
joelhardi

6
“ Windows没有此功能” ...确定吗?NT内核基于带有句柄和引用的引用对象。
亚当·米兹

10
Windows实际上有3位可以设置,它们定义了打开文件时另一个进程可以做什么。如果该FILE_SHARE_DELETE位置1,则可以在打开文件时将其删除。我认为PE加载程序(加载EXE和DLL)不会设置此位。这些句柄是按引用计数的,在删除最后一个句柄时,文件会消失,但是与Unix之间的区别是,当这种情况发生时,NT将阻止使用相同名称创建新文件。
asveikau

2
comonad所说的完全是错误的,NTFS当然使用了Hardlinks,而且总是这样做,在Windows Vista中已添加了符号链接。Windows不使用ref copunting完全是错误的,它确实这样做,只是读了诸如CreateFile之类的API,而明确指出了在什么情况下可以删除文件等等。这也是该问题的真实答案的合适位置:CreateFile具有一个参数dwShareMode,用于控制打开文件的强制锁定并由应用程序决定。默认值为排他锁...
ThorstenSchöning15年

29

据我所知,Linux 在运行时锁定可执行文件,但是会锁定inode。。这意味着您可以删除“文件”,但是inode仍在文件系统上,没有被修改,而您真正删除的只是一个链接。

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


“每时每刻”?有什么例子吗?
Mez

4
向Google查询“ unix安全临时文件”,您将找到对该技术的足够描述,以表明它是众所周知的和常用的。虽然我没有任何具体示例,但我敢说任何使用临时文件的注重安全的应用程序都可以做到这一点。
Dave Sherohman

26

Linux确实会锁定文件。如果您尝试覆盖正在执行的文件,则会得到“ ETXTBUSY”(文本文件忙)。但是,您可以删除该文件,并且在删除对该文件的最后一个引用时,内核将删除该文件。(如果未彻底关闭计算机,则在检查文件系统时,这些文件是“删除的inode的d时间为零”消息的原因,它们没有被完全删除,因为正在运行的进程已对其进行引用,现在他们是。)

这具有一些主要优点,您可以通过删除可执行文件,替换可执行文件然后重新启动进程来升级正在运行的进程。甚至init都可以像这样进行升级,替换可执行文件,并向其发送信号,然后它将重新执行exec()本身,而无需重新启动。(这通常是软件包管理系统在升级过程中自动完成的)

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

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

您也可以在Linux下使用此技巧来存储临时文件。打开文件,将其删除,然后继续使用该文件。当您的进程退出时(无论出于何种原因-甚至是电源故障),该文件都会被删除。

诸如lsof和fuser之类的程序(或只是在/ proc // fd中四处浏览)可以向您显示哪些进程中打开的文件不再具有名称。


6

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

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

我认为很大程度上是与window的文件系统向后兼容的问题。


在这种情况下,“ Windows”是Windows NT行。它被设计为单用户Windows 3.11的多用户继承者。与Unix相比,后者是Multics的单用户继承者。
MSalters

6

我认为您对Windows太过绝对了。通常,它不会为可执行文件的代码部分分配交换空间。而是,它在可执行文件和DLL上保持锁定。如果再次需要废弃的代码页,则只需重新加载它们即可。但是,使用/ SWAPRUN,这些页面将保持交换状态。这用于CD或网络驱动器上的可执行文件。因此,Windows不需要锁定这些文件。

对于.NET,请查看Shadow Copy


1

如果要锁定文件中的已执行代码是设计决定,而MS只是决定锁定,因为它在实践中具有明显的优势:这样,您无需知道哪个应用程序使用哪个版本的代码。这是Linux默认行为的一个主要问题,大多数人只是将其忽略。如果替换了系统范围的库,您将不容易知道哪些应用程序使用了这些库的代码,大多数情况下,您可以获得的最好的好处是,程序包管理器了解这些库的某些用户并重新启动它们。但这仅适用于一般的众所周知的事情,例如Postgres及其库等。更有趣的情况是,如果您针对某些第三方库开发自己的应用程序,而这些库则被替换了,因为大多数情况下,程序包管理器根本不了解您的应用程序。然后' 这不仅是本机C代码之类的问题,而且几乎所有情况都可能发生:只需将httpd与mod_perl一起使用,并使用软件包管理器安装一些Perl库,并让软件包管理器出于任何原因更新这些Perl库。它不会因为您不知道依赖关系而重启您的httpd。有很多这样的例子,仅仅是因为任何文件都可能包含任何运行时正在内存中使用的代码,请考虑一下Java,Python和所有类似的东西。

因此,有充分理由认为默认情况下锁定文件可能是一个不错的选择。不过,您无需同意这些理由。

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

请不要相信有人告诉您有关Windows的信息,而不是在句柄上使用引用计数或不支持硬链接等,这是完全错误的。几乎每个使用HANDLEs的API都记录了其与引用计数有关的行为,您几乎可以在几乎所有有关NTFS的文章中轻松地阅读到,它的确支持硬链接并且始终支持。从Windows Vista开始,它还支持符号链接,并且通过提供API来读取给定文件的所有API的方式,对硬链接的支持也得到了改进。

此外,与NTFS相比,您可能只想看看Ext4中用于描述文件的结构,而NTFS具有许多共同点。两者都适用于扩展区的概念,该区将数据与诸如文件名之类的属性分开,而inode几乎只是一个较旧但类似的概念的另一个名称。甚至Wikipedia在其文章中也列出了这两种文件系统。

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


共享依赖项的版本管理无关紧要。即使更新它们需要重新启动,您也必须处理这些问题。在Windows上,它甚至具有一个名称:DLL hell。此外,您描述的围绕它的运行时行为完全由Linux处理,在这种情况下,它已经将文件加载到内存中并且仍然可用。应用程序将一直使用旧版本运行,直到重新启动为止,就像Windows强制重新启动以解锁文件一样。在这方面没有优势。
jpmc26

DLL的地狱当然完全失去了重点,我们已经没有90了,只需阅读诸如此类的WinSxS东西。此外,这不是要把它们加载到内存中并保存在那里,Windows也会在必要时做到这一点,而是要知道并确定是否应该替换文件,以及由谁来决定。Windows-API只是让文件的第一个用户决定,这很有意义。
ThorstenSchöning19年

但这就是我的观点:决定使用哪个版本的DLL是DLL地狱的一部分。如果要与Windows的某些旧式行为区别开来,请称其为“依赖地狱”。无论如何,默认为锁定可执行文件都无助于管理共享依赖项。完全没有 当您尝试升级依赖于特定文件的文件时,它们甚至可能无法运行。没有额外的安全性。有共享依赖项的2种选择:所有人免费,在尝试运行时可能会损坏东西,或者程序包管理器有可能阻止您安装东西。
jpmc26

这个问题不是要决定要使用哪个EXE或DLL,而是默认之后会发生什么以及为什么。您正在讨论一个完全不同的主题。在决定执行哪个EXE或DLL之后,第一位用户(在本例中为Windows本身)获得某种级别的附加控制,并告知其他用户该控制之后,便使用锁定。出于某种原因,也不允许Windows删除或写入“其他文件”,因此将它们锁定,这当然是一种额外协调的机制。
ThorstenSchöning,

1
无论如何,某些EXE或DLL都不是“在内存中”,而是默认情况下映射到其中。映射要求文件内容可用,因此默认情况下随意替换它是不安全的,并且应该知道自己在做什么。如果有人对被锁定的EXE或DLL感到惊讶,则情况并非如此。OTOH,所有其他文件仅默认情况下处于锁定状态,因此应用程序可以根据使用情况决定是否允许您进行写入或删除操作。应用程序的开发人员应该比任意用户更了解他们如何使用他们的文件以及何时安全操作。
ThorstenSchöning,

0

NT变体具有

打开文件

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

打开文件/ local /?

告诉您如何执行此操作,以及这样做会导致性能下降。


0

可执行文件在运行时逐渐映射到内存。这意味着可执行文件的各个部分均按需加载。如果在映射所有节之前将文件换出,则可能导致严重的不稳定。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.