虚拟内存
虚拟内存为每个进程提供了一个大的、一致的和私有的地址空间。
虚拟内存提供了三个重要的能力:
- 将主存看成是一个存储在磁盘上的地址空间的高速缓存,在主存中只保存活动区域,并根据需要在磁盘和主存之间来回传送数据,通过这种方式,高效地使用主存。
- 为每个进程提供了一致的地址空间,简化了内存管理。
- 保护每个进程的地址空间不被其他进程破坏。
物理和虚拟寻址
-
计算机系统的主存被组织成一个由M个连续的字节大小的单元组成的数组。每字节都有一个唯一的物理地址(Physical Address, PA)。第一个字节的地址为0,以此类推。
-
CPU访问内存使用物理地址叫做物理寻址(Physical addressing):
-
CPU通过虚拟地址访问内存叫做虚拟寻址(Virtual Address, VA)。将虚拟地址转换为物理地址叫做地址翻译(address translation)。
地址空间
- 地址空间是一个非负整数地址的有序集合。
- 线性地址空间:空间中的整数是连续的,{0,1,2,3,…}
- 地址空间的大小用位表示:{1,2,3,…,N-1}叫做n位地址空间。现代系统通常支持32位或者64位虚拟地址空间。
- 虚拟内存思想:允许每个数据对象(字节)有多个独立的地址,其中每个地址都选自一个不同的地址空间。主存中的每字节都有一个选自虚拟地址空间的虚拟地址和一个选自物理地址空间的物理地址。
虚拟内存作为缓存的工具
-
虚拟内存:一个由存放在磁盘上的N各连续的字节大小的单元组成的数组。
-
磁盘上属于虚拟内存的数据被分割成块,这些块作为磁盘和主存之间的传输单元。
-
虚拟页(Virtual Page, VP):虚拟内存被分割为固定大小的块。
-
物理页(Physical Page, PP):物理内存被分割为固定大小的块,也被称为页帧。
-
在任意时刻,虚拟页面的集合都分为三个不相交的子集:
- 未分配的:VM系统还未分配(或者创建)的页。未分配的块没有任何数据和它们相关联,不占用任何磁盘空间。
- **缓存的:**当前已缓存在物理内存中的已分配页。
- **未缓存的:**未缓存在物理内存中的已分配页。
页表
- 页表将虚拟页映射到物理页,每次地址翻译硬件将一个虚拟地址转换为物理地址时,都会读取页表。页表就是一个页表条目(Page Table Entry, PTE)的数组。
页命中
- 使用虚拟地址作为页表的索引定位PTE2,根据有效位判断是否分配以及缓存,有效位为1说明已经在物理内存中缓存,所以使用PTE中的物理内存地址,构造出这个字的物理地址。
缺页
-
DRAM缓存不命中称为缺页,虚拟页面集合为未缓存。
-
触发缺页后,程序将VP4置位牺牲页,替换为VP3
虚拟内存作为内存管理的工具
-
操作系统为每个进程提供了一个独立的页表,也就是一个独立的虚拟地址空间。
多个虚拟页面可以映射到同一个共享物理页面上。
-
VM简化了链接和加载、代码和数据共享,以及应用程序的内存分配。
- 简化链接:独立的地址空间允许每个进程的内存映像使用相同的基本格式,而不管代码和实际存放在物理内存的何处。
- **简化加载:**虚拟内存使得容易向内存中加载可执行文件和共享对象文件。
- 简化共享:独立地址空间为操作系统提供了一个管理用户进程和操作系统自身之间共享的一致机制。
- **简化内存分配:**操作系统分配虚拟内存页面映射到物理内存,由于页表工作的方式,页面可以随机的分散在物理内存中。
虚拟内存作为内存保护的工具
-
每次CPU生成一个地址时,地址翻译硬件都会读一个PTE,通过在PTE上添加一些额外的许可位来控制对一个虚拟页面内容的访问。
-
SUP表示只有在超级用户(内核模式)下才能访问。
内存映射
- 内存映射:将一个虚拟内存区域与一个磁盘上的对象关联起来,以初始化这个虚拟内存区域的内容。
- 内存映射可以映射到两种类型的对象中的一种:
- Linux文件系统中的普通文件:虚拟内存区域被映射到一个普通磁盘文件的连续部分。
- 匿名文件:由内核创建的全是二进制零的文件。
- 虚拟页面初始化后,就在由内核维护的交换文件(交换空间、交换区域)中换来换去。交换空间限制着当前运行着的进程能够分配的虚拟页面的总数。
共享对象与内存映射
-
一个对象被映射虚拟内存的一个区域,要么作为共享对象,要么是私有对象。
-
不同进程对于映射到同一个共享对象的虚拟内存区域的任何写操作都是可见的。
-
私有对象使用写时复制的技巧被映射到虚拟内存中。
-
两个进程将一个私有对象映射到虚拟内存的不同区域,但是共享同一个物理内存副本。
对于每个映射私有对象的进程,相应私有区域的页表条目都被标记为只读,并且区域结构被标记为私有的写时复制。
当其中一个进程写私有的写时复制的页时,会在物理内存中创建这个页面的副本,然后更新进程2的页表条目指向这个新的副本,并且恢复这个新的副本的写权限。
动态内存分配
-
动态内存分配器维护者一个进程的虚拟内存区域,称为堆(heap)。
-
堆是块(block)的集合,块是连续的虚拟内存片(chunk),要么是已分配的,要么是空闲的。
-
释放已分配的块有两种方式:
- 显示分配器,显示的释放任何已分配的块,调用内置函数手动执行。
- 隐式分配器,高级语言中的垃圾处理机制。
. 显示分配器,显示的释放任何已分配的块,调用内置函数手动执行。
2. 隐式分配器,高级语言中的垃圾处理机制。