5

众所周知,mmap() 最重要的特性是文件映射在许多进程之间共享。但众所周知,每个进程都有自己的地址空间。

问题是内存映射文件(更具体地说,它的数据)真正保存在哪里,以及进程如何访问该内存?我的意思不是 *(pa+i) 和其他高级别的东西,而是指流程的内部。

4

5 回答 5

10

这发生在操作系统的虚拟内存管理层。当您对文件进行内存映射时,内存管理器基本上将该文件视为进程的交换空间。当您访问虚拟内存地址空间中的页面时,内存映射器必须解释它们并将它们映射到物理内存。当你越过页面边界时,这可能会导致页面错误,此时操作系统必须将一块磁盘空间映射到一块物理内存并解析内存映射。使用 mmap,它只是从您的文件而不是它自己的交换空间中执行此操作。

如果您想详细了解这是如何发生的,您必须告诉我们您使用的是哪个操作系统,因为实现细节会有所不同。

于 2009-04-20T18:00:32.570 回答
6

这是非常依赖于实现的,但以下是一种可能的实现:

当文件是第一个内存映射时,数据一开始并没有存储在任何地方,它仍然在磁盘上。虚拟内存管理器 (VMM) 为文件的进程分配一系列虚拟内存地址,但这些地址不会立即添加到页表中。

当程序第一次尝试读取或写入其中一个地址时,会发生页面错误。操作系统捕获页面错误,确定该地址对应于内存映射文件,并将适当的磁盘扇区读入内部内核缓冲区。然后,它将内核缓冲区映射到进程的地址空间,并重新启动导致页面错误的用户指令。如果错误指令是读取,我们现在都完成了。如果是写入,则将数据写入内存,并将页面标记为脏页。对同一页内的数据的后续读取或写入不需要从磁盘读取/写入/从磁盘读取/写入,因为数据在内存中。

当文件被刷新或关闭时,任何被标记为脏的页面都会被写回磁盘。

使用内存映射文件对于以非常随意的方式读取或写入磁盘扇区的程序是有利的。您只读取实际使用的磁盘扇区,而不是读取整个文件。

于 2009-04-20T18:03:43.200 回答
0

内核具有表示内存块的内部缓冲区。任何给定的进程都在其自己的地址空间中分配了一个内存映射,该地址空间引用该缓冲区。许多进程可能有自己的映射,但它们最终都解析为同一个块(通过内核缓冲区)。

这是一个足够简单的概念,但在进程写入时可能会有点棘手。为了在只读情况下保持简单,通常有一个仅在需要时使用的写时复制功能。

于 2009-04-20T18:02:37.900 回答
0

我不太确定你在问什么,但是 mmap() 预留了一块虚拟内存来保存给定数量的数据(通常。它有时可以是文件支持的)。

进程是操作系统实体,它通过操作系统禁止的方法获得对内存映射区域的访问权限:调用 mmap()。

于 2009-04-20T18:01:26.593 回答
0

任何数据都将存储在某种形式的内存或其他形式中,在 HDD 中的某些情况下,在嵌入式系统中可能是一些闪存甚至 RAM(initramfs),除非最后一个,内存中的数据经常缓存在 RAM 中, RAM 在逻辑上被划分为页面,内核维护一个唯一标识页面的描述符列表。

因此,充其量访问数据将是访问物理页面。进程到达那里自己的进程地址空间,该地址空间由许多 vm_are_struct 组成,这些 vm_are_struct 标识地址空间中的映射部分。在对 mmap 的调用中,可能会创建新的 vm_area_struct,或者如果地址相邻,则可能与现有的 vm_area_struct 合并。

一个新的虚拟地址被返回给对 mmap 的调用。还创建了新的页表,其中包括将新创建的虚拟地址映射到真实数据所在的物理地址。映射可以在文件上完成,也可以像 malloc 一样匿名。进程地址空间结构mm_struct使用pgd_t(Page global directory)的指针到达物理页并访问数据。

于 2015-10-27T12:09:42.797 回答