什么是内存映射页面和匿名页面?

时间:2012-10-23 05:27:31

标签: linux memory-management linux-kernel

我无法理解linux中的内存映射页面和匿名页面。有人可以用一个例子解释一下吗?与它们相关的内核数据结构是什么?

3 个答案:

答案 0 :(得分:49)

正确的术语是内存映射的文件和匿名映射。当提到内存映射时,通常是指mmap(2)。使用mmap有两个类别。一个类别是SHARED与PRIVATE映射。另一类是FILE vs ANONYMOUS映射。混合在一起可以获得以下4种组合:

  1. 私人文件映射
  2. 共享文件映射
  3. 私人匿名映射
  4. 共享无名映射
  5. 文件映射指定磁盘上的文件,该文件将N个字节映射到内存中。函数mmap(2)将要映射到内存的文件的文件描述符作为其第4个参数。第五个参数是要读入的字节数,作为偏移量。使用mmap创建内存映射文件的典型过程是

    1. 打开(2)文件以获取文件描述符。
    2. fstat(2)从文件描述符数据结构中获取大小的文件。
    3. mmap(2)使用从open(2)返回的文件描述符的文件。
    4. close(2)文件描述符。
    5. 对内存映射文件执行任何操作。
    6. 当文件作为PRIVATE映射时,所做的更改不会提交到基础文件。它是文件的PRIVATE内存副本。当文件映射为SHARED时,内核会自动将更改提交给基础文件。以共享方式映射的文件可用于所谓的内存映射I / O和IPC。如果需要文件的持久性

      ,可以使用IPC的内存映射文件而不是共享内存段

      如果使用strace(1)来监视进程初始化,您会注意到使用mmap(2)将文件的不同部分映射为私有文件映射。系统库也是如此。

      strace(1)的输出示例,其中mmap(2)用于将库映射到流程。

      open("/etc/ld.so.cache", O_RDONLY)      = 3
      fstat(3, {st_mode=S_IFREG|0644, st_size=42238, ...}) = 0
      mmap(NULL, 42238, PROT_READ, MAP_PRIVATE, 3, 0) = 0x7ff7ca71e000
      close(3)                                = 0
      open("/lib64/libc.so.6", O_RDONLY)      = 3
      read(3, "\177ELF\2\1\1\3\0\0\0\0\0\0\0\0\3\0>\0\1\0\0\0p\356\341n8\0\0\0"..., 832) = 832
      fstat(3, {st_mode=S_IFREG|0755, st_size=1926760, ...}) = 0
      mmap(0x386ee00000, 3750152, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0) = 0x386ee00000
      

      匿名映射不受文件支持。具体而言,当MAP_ANONYMOUS标志用作mmap(2)的第3个参数时,甚至不使用mmap(2)的第4个(文件描述符)和第5个(偏移量)参数。使用MAP_ANONYMOUS标志的另一种方法是使用/ dev / zero作为文件。

      匿名'对我来说,这是一个糟糕的选择,因为它听起来好像文件是匿名映射的。相反,它是匿名的文件,即。没有指定文件。

      私有匿名映射在用户域编程中的用途很少。您可以使用共享匿名映射,以便应用程序可以共享内存区域,但我不知道您不会使用SYSV或POSIX共享内存的原因。

      由于使用匿名映射映射的内存保证为零填充,因此对于某些期望/要求零填充内存区域的应用程序以这种方式使用mmap(2)而不是malloc(2)+可能很有用memset(2)combo。

答案 1 :(得分:7)

据我所知,匿名页面是这样命名的,因为它们没有命名文件系统源,而映射页面是具体文件的映射。例如,您可以在任何用户空间进程中使用简单的malloc操作来获取匿名页面...

关于内核结构: 显然它是 struct page ,但是在anonymos页面的情况下,您将在page->映射中使用 struct anon_vma ,并且在映射页面的情况下 - struct address_space ,它与具体的inode连接。

答案 2 :(得分:1)

我不确定内存映射页面是什么意思?所以我不再谈论它。

关于匿名页面,通常在内核执行页面框架回收时引用。匿名页面的实例包括进程的堆栈,堆,共享内存以及任何修改后的共享库。在Linux中,所有动态共享库都通过如下所示的系统调用映射到进程的虚拟内存地址空间:

firo@linux-6qg8:~> strace -e mmap,openat ls 2>&1 |grep -A1 libc.so
openat(AT_FDCWD, "/lib64/libc.so.6", O_RDONLY|O_CLOEXEC) = 3
mmap(NULL, 3906144, PROT_READ|PROT_EXEC, MAP_PRIVATE|MAP_DENYWRITE, 3, 0)

任何属于MAP_PRIVATEed文件/库的页面上的写操作都会触发从文件后端页面到匿名页面的更改。

根据定义,匿名页面也称为匿名内存,只是一种页面,当内核执行页面框架回收时,该页面没有后端设备可以交换。这就是Linux支持交换区域的原因。

与匿名页面有关的内核数据结构有两种。

  1. 为了回收匿名页面,内核必须知道所有使用匿名页面更改其PTE(页面表条目)的进程。我们称其为反向映射或rmap。

    共享内存使用

    struct address_space维护反向映射。

    其余匿名页面使用

    struct anon_vma来维护反向映射。

  2. 内核使用LRU算法回收页面框架。 对于内核5.0及更高版本,请检查struct pglist_data中的struct lruvec