第九章 虚拟内存 第八节 内存映射

1、内存映射概述

Linux 通过将一个虚拟内存区域与一个磁盘上的对象(object) 关联起来,以初始化这个虚拟内存区域的内容,这个过程称为内存映射(memory mapping)。虚拟内存区域可以映射到两种类型的对象中的一种:

1. Linux文件系统中的普通文件

一个区域可以映射到一个普通磁盘文件的连续部分,例如一个可执行目标文件。
文件区(section)被分成页大小的片,每一片包含一个虚拟页面的初始内容。因为按需进行页面调度,所以这些虚拟页面没有实际交换进入物理内存,直到CPU第一次引用到页面(即发射一个虚拟地址,落在地址空间这个页面的范围之内)。如果区域比文件区要大,那么就用零来填充这个区域的余下部分。

2. 匿名文件

一个区域也可以映射到一个匿名文件,匿名文件是由内核创建的,包含的全是二进制零。CPU第一次引用这样一个区域内的虚拟页面时,内核就在物理内存中找到一个合适的牺牲页面,如果该页面被修改过,就将这个页面换出来,用二进制零覆盖牺牲页面并更新页表,将这个页面标记为是驻留在内存中的。注意在磁盘和内存之间并没有实际的数据传送。因为这个原因,映射到匿名文件的区域中的页面有时也叫做请求二进制零的页(demand-zero page) 。

2、内存映射应用之共享对象

对于每个进程,它既有与其他进程的相同的代码(如c的库函数),又有一些私有的代码区域。
一个对象可以被映射到虚拟内存的一个区域, 要么作为共享对象, 要么作为私有对象。如果一个进程将一个共享对象映射到它的虚拟地址空间的一个区域内, 那么这个进程对这个区域的任何写操作, 对于那些也把这个共享对象映射到它们虚拟内存的其他进程而言, 也是可见的。而且, 这些变化也会反映在磁盘上的原始对象中。

另一方面, 对一个映射到私有对象的区域做的改变, 对千其他进程来说是不可见的, 并且进程对这个区域所做的任何写操作都不会反映在磁盘上的对象中。一个映射到共享对象的虚拟内存区域叫做共享区域。类似地, 也有私有区域。

1. 共享对象

第九章 虚拟内存 第八节 内存映射_第1张图片
假设进程1已经将共享对象映射到他的虚拟内存中。此时进程2也要将该部分内容映射到其虚拟内存中,因为每个对象都有一个唯一的文件名。所以内核知道该对象已经被进程1映射,并让进程2中的页表条目指向对应的物理页面。

这样物理内存中只需要存放一个共享对象的副本即可。

2. 私有对象

私有对象使用一种叫做写时复制的技术映射在虚拟内存中。
第九章 虚拟内存 第八节 内存映射_第2张图片
如图中的情况。一开始两个进程都将一个私有对象映射到他们虚拟内存的不同区域,但是共享一个物理副本。对于每个映射私有对象的进程, 相应私有区域的页表条目都被标记为只读, 并且区域结构(area)被标记为私有的写时复制。

只要没有进程试图写它自己的私有区域, 它们就可以继续共享物理内存中对象的一个单独副本。然而, 只要有一个进程试图写私有区域内的某个页面, 那么这个写操作就会触发一个保护故障。

当故障处理程序注意到保护异常是由于进程试图写私有的写时复制区域中的一个页面而引起的, 它就会在物理内存中创建这个页面的一个新副本, 更新页表条目指向这个新的副本, 然后恢复这个页面的可写权限, 如图9-30b所示。当故障处理程序返回时, CPU重新执行这个写操作, 现在在新创建的页面上这个写操作就可以正常执行了。

这样最大限度地节约了物理内存。

3、再看fork函数

当fork函数被当前进程调用时, 内核为新进程创建各种数据结构, 并分配给它一个唯一的PID。为了给这个新进程创建虚拟内存, 它创建了当前进程的mm_struct、区域结构和页表的原样副本。它将两个进程中的每个页面都标记为只读, 并将两个进程中的每个
区域结构都标记为私有的写时复制。

当fork在新进程中返回时, 新进程现在的虚拟内存刚好和调用fork时存在的虚拟内存相同。当这两个进程中的任一个后来进行写操作时, 写时复制机制就会创建新页面,因此, 也就为每个进程保持了私有地址空间的抽象概念。

4、使用mmap函数的用户级内存映射

第九章 虚拟内存 第八节 内存映射_第3张图片
第九章 虚拟内存 第八节 内存映射_第4张图片

1. 参数解释

  1. start
    要求最好是从start这个地址开始的一个区域。通常设置为null,仅仅做一个暗示。
  2. fd及length、offset
    将文件描述符fd指定的对象的一个连续的片映射到这个区域。其大小为length,距离文件开始处偏移offset字节的地方开始。
  3. prot
    包含描述新映射的虚拟内存区域的访问权限位(即在相应区域结构中的vm_prot 位)
    在这里插入图片描述
  4. flag
    描述被映射对象类型的位组成。
    MAP_ANON标记位,那么被映射的对象就是一个匿名对象, 而相应的虚拟页面是请求二进制零的
    MAP_PRIVATE表示被映射的对象是一个私有的、写时复制的对象
    MAP_SHARED表示个共享对象

你可能感兴趣的:(深入理解计算机系统读书笔记,深入理解计算机系统,虚拟内存,内存映射)