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

Linux 什么是内存映射页和匿名页?,linux,memory-management,linux-kernel,Linux,Memory Management,Linux Kernel,我无法理解linux中的内存映射页和匿名页。有人能举例说明一下吗?与它们相关的内核数据结构是什么?据我所知,匿名页面之所以这样命名,是因为它们没有命名的文件系统源,而映射页面是具体文件的映射。例如,您可以在任何用户空间进程中使用简单的malloc操作获取匿名OS页面 关于内核结构: 显然,它是结构页面,但对于匿名操作系统页面,您将在页面->映射中使用结构anon_vma,对于映射页面,结构地址空间,它与具体的索引节点相连。正确的术语是内存映射文件和匿名映射。当提到内存映射时,通常指的是mmap(

我无法理解linux中的内存映射页和匿名页。有人能举例说明一下吗?与它们相关的内核数据结构是什么?

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

关于内核结构:
显然,它是结构页面,但对于匿名操作系统页面,您将在页面->映射中使用结构anon_vma,对于映射页面,结构地址空间,它与具体的索引节点相连。

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

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

  • 打开(2)个文件以获取文件描述符
  • fstat(2)从文件描述符数据结构获取大小的文件
  • mmap(2)使用从open(2)返回的文件描述符的文件
  • 关闭(2)文件描述符
  • 对内存映射文件执行任何操作
  • 将文件映射为专用文件时,所做的更改不会提交到基础文件。它是文件的私有内存副本。当文件映射为共享时,内核会自动将所做的更改提交到基础文件。映射为共享的文件可用于所谓的内存映射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_匿名标志用作mmap(2)的第三个参数时,mmap(2)的第四个(文件描述符)和第五个(偏移量)参数甚至没有使用。使用MAP_匿名标志的另一种方法是使用/dev/zero作为文件

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

    在用户土地编程中很少使用私有匿名映射。您可以使用共享匿名映射,以便应用程序可以共享一个内存区域,但我不知道为什么您不使用SYSV或POSIX共享内存


    由于使用匿名映射中映射的内存保证为零填充,因此对于一些希望/需要零填充内存区域的应用程序来说,以这种方式使用mmap(2)而不是malloc(2)+memset(2)组合是很有用的。

    我不确定内存映射页的含义是什么?所以我不打算谈论它

    关于匿名页面,当内核进行页面框架回收时,通常会提到匿名页面。匿名页的实例包括进程的堆栈、堆、共享内存和任何修改过的共享库。在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_私有文件/库的页面的任何写入都将触发从文件后端页面更改为匿名页面

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

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

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

    共享内存使用结构地址空间来维护反向映射

    其余匿名页面使用struct anon_vma来维护反向映射

  • 内核使用LRU算法回收页面帧。 对于内核5.0+,请检查struct pglist_数据中的struct lruvec


  • mmaped file是页面缓存支持的虚拟内存页面;匿名页面(带有标志MAP_anonymous的mmap)是虚拟内存页面,由零页面支持(读取时只返回零;写入被标志禁止)。当您第一次写入匿名页面时,新的物理页面将被分配并用零填充。此页面将映射到您的anon。页面和写入操作将重新启动。请尝试以下操作:(此处为完整书籍:)作为联机书籍;或者将Daniel P.Bovet的Linux内核理解为离线书籍(我认为它是注释过的内核源代码列表)?任何实例或引用?回答得好,但我认为问题应该是指匿名页面和页面缓存中的页面。它们不是用户空间的东西。