对应视频内容:
https://www.bilibili.com/video/BV1uW411f72n?p=21&spm_id_from=pageDriver
4.1 非连续内存分配:分段
4.2 非连续内存分配:分页
4.3 非连续内存分配:页表-概述、TLB
4.4 非连续内存分配:页表-二级,多级页表
4.5 非连续内存分配:页表-反向页表
一、为什么需要非连续内存分配
连续分配有碎片等缺点。
非连续分配的优劣
优点:
- 一个程序的物理地址空间是非连续的;
- 更好的内存利用和管理;
- 允许共享代码与数据(共享库etc.);
- 支持动态加载和动态链接。
缺点:
- 如何建立虚拟地址和物理地址之间的转换
- 软件方案(开销巨大)
- 硬件方案(主要考虑的方案)
硬件方案: 分段、分页。
二、分段(segment)
根据程序的段的性质,分离出来管理。
段的分离技术
堆、运行栈、程序数据、程序text段分开管理,确保了效率、安全问题。
- 逻辑地址是连续的地址空间
- 物理地址是不连续的地址空间
分段的逻辑视图
分段技术是一种映射。使用 硬件支持 来寻址,是一种较好方案。
分段寻址方案
- 一维的逻辑地址如何映射到物理地址。
s: segment number,段号;
addr: address,地址。
x86为段寄存器+地址寄存器实现方案。
- 逻辑地址分成两块
- 第一块为段号
- 第二块为偏移地址
上图中,左上角应用程序P通过CPU执行每条指令;CPU去寻址,这里采用单地址实现方案。
- 段号保存在 段表 (存储:逻辑地址与物理地址映射关系;每个段起始地址、长度限制)里,段号决定段表中的索引。段表是操作系统在寻址之前就建立好的。
注意:由于段的长度是不确定的,所以段表中会存储段的起始地址和长度的限制.
段表是由操作系统进行建立的。
段表如何建立在实验部分展开讲解。
三、分页(paging)
分段和分页的区别
- 分段中,每段的长度是不确定的。
- 分页中,每页的长度是确定的。
分页为较为常用方式。分页机制中,“段”的尺寸不可变,即为页。
基本规定
-
划分物理内存至固定大小的帧:大小是2的幂,e.g.,512,4096,8192。
-
划分逻辑地址空间至相同大小的页:大小是2的幂,e.g.,512,4096,8192。
-
逻辑地址和物理地址中页的大小是相同的,便于硬件做相应的实现。
注意:
帧(frame)表示物理页
页(page)表示逻辑页
建立方案:转换逻辑地址为物理地址(pages to frames)
- 页表
- MMU/TLB
- 帧(Frame)
帧(物理地址)
物理内存被分割为 大小相等的帧 。帧存在帧号(frame number)与偏移(offset),相当于段中的段号与偏移。 帧号占了F这么多位,本身大小占了S这么多位。
地址计算的实例
上图示例中,(f,o)=(3,6),分别代表段号与本身所表示值。
页(逻辑地址)
逻辑地址中,用页表示。
- 在页中, 页号大小可能不等于帧号大小,但是偏移大小一定相等。
页选址机制
有了页号,查出帧号是多少。(p,o)→(f,o)。页表由操作系统建立。
分页机制,每页偏移大小固定,没有分段中存在的异常问题。一般来讲,逻辑地址空间大于物理内存地址空间,会产生问题,解决办法在虚拟内存中讨论。
page table:
- 存储了页号所对应的帧号。
- 需要页表基址,需要知道在哪里找到页表
- 有助于减少内存碎片
- 逻辑地址空间大于物理地址空间,如果物理地址空间不够用了,怎么办?
四、页表
问题:
- 如何使得页表高效
- 如何使得页表更加节省空间
页表结构
-
页表其实是一个大数组。
-
每个运行的程序都有一个页表。
page -> frame
上图中可以看到,页表项中存在一些bit,用于表示页的性质,如该页是否真实存在等等。
- Flags(标志位)
- dirty bit
- resident bit
- clock/reference bit
resident bit(驻留位),1代表页存在;Frame num是00100,对应物理地址f是4。
地址转换实例
- 对于(4,0)逻辑地址来说,resident bit为0,表示物理帧不存在,会产生一个内存访问的异常
- 对于(3,1023),resident bit为1,对应的物理页帧确实存在,页帧号为4,所以物理地址为(4,1023)
总结:对于页表来说存在两种情况
- 物理页帧存在
- 物理页帧不存在
分页机制的性能问题
对于页表使用来说,
- 内存占用越少越好
- 查找速度越快越好
问题:
访问一个内存单元需要2次访问(空间开销大)
-
一次用于获取页表项;
一次用于访问数据。
eg. 64位机器如果每页1024字节,那么一个页表大小是2的64次方/1024=2的54次方,过大。如果这样,计算机连一个页表都存不下。 -
并且,CPU的cache很小(几M),放不下多个应用程序的多个列表。
-
如果页表只能放在内存中,做内存寻址需要两次内存访问。
如何解决分页机制的性能问题
- 缓存(Caching);
- 间接(Indirection)访问。
TLB
TLB: translation look-aside buffer
- 位于cpu的内部
- cpu中的块表TLB
- 将经常需要访问的页帧映射关系,直接保存在TLB中,可以减少对页表的访问
-
常用页放在TLB中,直接映射到物理地址,也避免了对内存中页表的访问。
-
如果TLB访问不到(TLB miss),CPU回去查页表。TLB缺失不会很大
-
TLB缺失不会很大的,因为一个页在32位系统是4K的大小,一般需要访问4K次,才会出现缺页现象
-
写程序时,尽量保证了访问的局部性。
二级页表
通过多级页表,缓解页表的占用空间。
- 二级页表中,将大的page号,切割成两块p1, p2。
- 如果一级页表中,某一个p1项的resident bit为零,表示物理页帧不存在,因为二级页表不需要创建出来,不需要占用内存空间,可以极大节省空间
一级页表中不存在的索引,二级页表中也没有必要存在,因此节省了空间。
多级页表
多级页表的思想方式为:
- 时间换取空间的手段
多级页表中,存在“树”状关系。像64位系统中,使用5级页表进行存储。 尽管访问级数越高,时间开销越大,但是节省了空间。而时间的开销又可以通过TLB机制缓解。
五、反向页表(inverted page table)
-
使页表的大小与逻辑地址大小没有那么大的关系,跟物理地址大小相关。
-
有大地址空间(64-bits,64位寻址空间),前向映射页表变得繁琐(如5级页表)。
-
不是让页表与逻辑地址空间的大小相对应,而是让页表与物理地址空间的大小相对应。
-
逻辑(虚拟)地址空间增长速度快于物理地址空间。
基于页寄存器的方案
因此,以物理页的页帧号作为index,来查找逻辑页的页号。
办法一:基于页寄存器(Page Registers)的方案
寄存器中,以帧号为索引。寄存器大小只与物理地址有关。占的空间很少。
使用页寄存器
页寄存器一个例子:
物理内存大小:4096×4096=4K×4KB=16MB
页面大小:4096bytes=4KB
页帧数:4096=4K
页寄存器使用的空间(假设8 bytes/register):8×4096=32Kbytes
页寄存器带来的额外开销:32K/16M=0.2%
虚拟内存大小:任意
但是在查找时,是根据Page number来查找Frame number。
因此,页寄存器该如何查找?
基于关联内存的方案(associative memory)的方案
关联存储器虽然解决了查找问题,但是设计复杂,需要放到CPU中(放到内存中存在访问开销问题),开销代价巨大。
基于哈希(hash)查找的方案
哈希计算一般使用硬件辅助计算加速。加入PID(程序ID)参数及哈希规则,有效缓解映射开销。
存在哈希碰撞问题,需要使用PID缓解这种冲突;
反向页表还是要放到内存中,还是需要TLB把其缓存起来。
这种机制(反向页表、不受制于虚拟地址空间限制)在高端CPU中才存在。
外链图片转存中…(img-wNUEv6HB-1640836730932)]
关联存储器虽然解决了查找问题,但是设计复杂,需要放到CPU中(放到内存中存在访问开销问题),开销代价巨大。