如何判断文件是否是内存映射的?

Utk*_*tku 9 memory files

我对内存映射文件感到困惑,所以我有几个问题,如果你能帮助我,我会很高兴。

  1. 假设我浏览到文件系统中的一个目录,并且该目录中有一个文件。这个文件是否有可能指向主内存中的一个区域,而不是指向磁盘中的一个区域?
  2. 如果这是可能的,这就是我们所说的“内存映射文件”吗?
  3. 在文件系统中移动此类文件(即将mv此类文件从一个目录移入另一个目录)有什么意义?我的理解是,由于文件是内存映射的,与文件交互的进程总是写入主内存的预定义区域,当我们打开该文件(例如使用vim)时,我们读取该区域的 main内存(因此,不涉及磁盘)。因此,无论我们将文件移到何处,它始终都能正常工作,对吗?如果是,在文件系统中移动文件是否有意义?
  4. 是否有一个命令可以判断文件是否已进行内存映射?
  5. 最后,如果我用 打开一个内存映射文件vim,对其进行一些更改并保存并关闭vim,会发生什么?我的更改会简单地写入主内存吗?如果是这种情况,使用此文件的其他进程会看到我刚刚所做的更改吗?根据我的经验,当我对文件进行一些更改时,其他进程没有看到我对文件所做的更改vim。这是什么原因?

Ste*_*itt 24

内存映射文件反过来工作。内存映射不是文件的属性,而是访问文件的一种方式:进程可以将文件的内容(或其子集)映射到其地址空间。这使得读取和写入文件更容易;这样做只涉及在内存中读取和写入。磁盘上的文件本身与任何其他文件相同。

为了设置它,进程使用该mmap函数。这也可以用于其他目的,例如在进程之间共享内存。

  • @Utku 这与内存映射文件无关。 (14认同)
  • 如果你没有关闭 MySQL 服务器,那是正常行为:服务器在文件上打开了一个文件描述符,即使使用 `mv`,它仍然有效。 (12认同)
  • 文件描述符(最终)指向文件系统中的 inode;那就是文件真正存在的地方。目录条目也指向这些 inode,并且 `mv` 只是更改目录条目,而不是 inode(当它在同一文件系统上移动文件时)。 (11认同)
  • @Utku 你实际上并没有移动文件。您刚刚创建了一个引用同一文件的新目录条目,然后删除了旧目录条目。命名更改对已打开文件的进程没有影响。 (3认同)

lge*_*get 11

内存映射文件(必然)不受内存支持。它可以完美地存在于磁盘上。实际上,文件所在的位置不是文件本身的属性,而是它所在的文件系统的属性。

在内存中映射文件是一个进程可以执行的操作,以便将文件的一部分加载到内存中。结果看起来像一个常规的内存区域,不同的是当进程读取或写入该区域时,它实际上是读取和写入文件。如果你打开一个文件,将它映射到内存,写入它并保存它,修改将在文件上完成,在磁盘上(当然,如果它存在于磁盘上)。

例如,当您知道要对文件进行大量访问时,可以使用此方法,这些访问不会是连续的,因为在内存中进行读取和写入比发出read, write,和llseek系统调用。这种方法的唯一问题是,如果文件需要由多个进程同时读取或写入,则您无法真正使用它。结果将是不可预测的。

我不知道任何命令可以告诉您当前是否已映射文件。但是,您可以检查进程的映射/proc/<pid>/maps(如果您的系统有)。

回答你的第二个问题,当你打开一个文件时,即使你在文件系统中移动它,打开它的进程仍然可以使用它。发生的情况是文件不依赖于它在文件系统中的条目。只要你打开了一个文件,你就有一个“句柄”,一个文件描述符,它允许你读取和写入它,即使它在文件系统中的路径发生变化。文件只有在文件系统中没有条目并且没有进程在其上保存文件描述符时才会消失。


小智 10

Q4:是否有一个命令可以判断一个文件是否是内存映射的?

lsof命令将显示系统当前正在使用的所有文件。如果文件是内存映射的,则“FD”列将包含“mem”。因此,您可以为您感兴趣的文件名搜索此命令的输出。

  • 或者更确切地说是 `lsof -ad mem,txt /path/to/file` 作为正在执行的文件,它们的一部分也被映射到进程地址空间中,但在 `lsof` 输出中显示为 `txt`。 (5认同)
  • 或者使用`lsof -ad mem /path/to/file` (3认同)

JoL*_*JoL 7

您似乎将内存映射与内存驻留文件系统中的文件以及其他概念混淆,例如进程如何在文件四处移动时保持对文件的访问。

我会逐个提问,看看我是否可以解决问题。

  1. 假设我浏览到文件系统中的一个目录,并且该目录中有一个文件。这个文件是否有可能指向主内存中的一个区域,而不是指向磁盘中的一个区域?

如果它位于内存驻留文件系统上,则它确实指向主内存,例如通常挂载在 /proc 上的 procfs,或位于 /sys 上的 sysfs,或有时位于 /tmp 上的 tmpfs。

  1. 如果这是可能的,这就是我们所说的“内存映射文件”吗?

不。就像 stephen-kitt 所说,“内存映射”是指通过将文件“映射”到主内存并在那里使用它来访问文件的方法,而不是通过 read() 和写()。

  1. 在文件系统中移动此类文件(即将此类文件从一个目录移动到另一个目录)有什么意义?我的理解是,由于文件是内存映射的,与文件交互的进程总是写入主内存的预定义区域,当我们打开该文件(例如使用 vim)时,我们读取该区域主内存(因此,不涉及磁盘)。因此,无论我们将文件移到何处,它始终都能正常工作,对吗?如果是,在文件系统中移动文件是否有意义?

如果你在同一个文件系统中移动它,你实际上只是在一个引用,一个从一个目录到另一个目录的 inode 移动。如果有些程序已经打开了这个文件,它们仍然会访问同一个文件,因为它们已经通过文件描述符拥有了 inode。这就是您在评论中提到的 table_name.idb 文件发生的情况。

  1. 是否有一个命令可以判断文件是否已进行内存映射?

Wossname 已经为内存映射文件回答了这个问题。lsof将告诉您哪些进程具有文件内存映射。

要知道文件是否在驻留在内存的文件系统中,您可以使用dfmount列出文件系统及其挂载点。您只需要通过查找(例如在维基百科中)来知道哪些类型的文件系统驻留在内存中。

  1. 最后,如果我用 vim 打开一个内存映射文件,对其进行一些更改并保存并关闭 vim,会发生什么?我的更改会简单地写入主内存吗?如果是这种情况,使用此文件的其他进程会看到我刚刚所做的更改吗?根据我的经验,当我使用 vim 对文件进行一些更改时,其他进程没有看到我对文件所做的更改。这是什么原因?

就我个人而言,我没有mmap在 C 程序中使用过该函数,但正如我从略读man mmap和理解的那样info mmap,保持内存中表示的同步并没有什么神奇之处。在其基本形式中,调用 mmap 将文件内容复制到内存并msync用于将其从内存写回到磁盘。如果磁盘上的文件发生更改,则无法检测到并自动修改映射它的所有进程中的内存表示。

编辑:原来 mmap() 实际上确实尝试在某些条件下保持内存中的表示同步。如果只读取映射,即使其他进程写入文件,它也会保持同步。如果它被写入(通过分配给内存区域),会发生什么取决于提供给 mmap() 的明显强制的 MAP_SHARED 或 MAP_PRIVATE 标志中的哪一个。如果提供了 MAP_PRIVATE,则映射从磁盘表示中分叉并停止同步,直到您使用 msync()。如果提供了 MAP_SHARED,则更新对映射文件的其他进程以及(尽管这不一定是立即的)磁盘表示可见。

我刚刚在现有文件上打开 vime并运行命令:w,同时inotifywait -m .在另一个终端中运行。在一些奇怪的部分中,这是我从inotifywait.

./ MOVED_FROM e
./ MOVED_TO e~
./ CREATE e
./ OPEN e
./ MODIFY e
./ CLOSE_WRITE,CLOSE e
./ ATTRIB e
./ ATTRIB e
./ DELETE e~
Run Code Online (Sandbox Code Playgroud)

Vim 创建一个新文件,并删除旧文件。为什么这样做而不是修改文件超出了这个问题的范围,但关键是这是一个新文件,因此有一个新的 inode。

现在,使用此文件的其他进程是什么意思?如果您的意思是在您执行此操作时打开了文件的进程,那么他们不会看到更改。这是因为,虽然它们打开了一个路径相同的文件,但它们不是同一个文件。如果您的意思是在您执行此操作后可能会打开文件的进程,那么是的,他们会看到更改。他们将打开您创建的新文件。

重要的是要注意,虽然程序似乎在用户界面上打开了一个文件,但这并不一定意味着它们在此过程中保持文件打开。Vim 就是一个例子,如上所示。

  • “*如果磁盘文件发生变化,则没有任何东西可以检测到并自动修改映射它的所有进程中的内存表示。*”什么会改变操作系统背后的磁盘文件系统页面映射系统?您是否在想象对块设备或通过 iSCSI 共享的块设备或其他东西的原始访问? (3认同)