分段
1、分段的思想:
- 给地址空间内的每个逻辑段(segment)一个基址和界限寄存器对。
- 在典型的地址空间里有 3 个逻辑不同的段:代码、栈和堆。
- 分段的机制使得操作系统能够将不同的段放到不同的物理内存区域,从而避免了虚拟地址空间中的未使用部分占用物理内存。
2、代码段、堆段、栈段物理地址:
代码段和堆段的物理地址 = 虚拟地址 - 偏移量 + 物理基址(正向增长)
根据上图求堆中虚拟地址4200的物理地址?
解:
4200 - 4(KB) + 34(KB) = 34920
栈段的物理地址 = 物理基址 - (虚拟地址 - 偏移量)(反向增长)
根据上图求栈中虚拟地址15KB的物理地址?
解:
28KB - (15KB - 14KB) = 27KB
3、支持共享:
为了支持共享,需要一些额外的硬件支持,这就是保护位(protection bit)。基本为每个段增加了几个位,标识程序是否能够读写该段,或执行其中的代码。通过将代码段标记为只读,同样的代码可以被多个进程共享,而不用担心破坏隔离。
4、管理物理内存的空闲空间:
- 一种解决方案是紧凑(compact)物理内存,重新安排原有的段。内存紧凑成本很高,因为拷贝段是内存密集型的,一般会占用大量的处理器时间。
- 另一种解决方案是利用空闲列表管理算法,试图保留大的内存块用于分配。无论 算法多么精妙,都无法完全消除外部碎片,因此,好的算法只是试图减小它。包括分配空间的空闲块返回)、最坏匹配(worst-fit)、首次匹配(first-fit)以及像伙伴算法(buddy algorithm)等等。
分页:介绍
1、分页的思想:将空间分割成固定长度的分片。把物理内存看成是定长槽块的阵列,叫作页帧(page frame)。
2、分页的优点:提供空闲空间管理的简单性和灵活性(操作系统能够高效地提供地址空间的抽象,不管进程如何使用地址空间。)
3、页表:
- 为了记录地址空间的每个虚拟页放在物理内存中的位置,操作系统通常为每个进程保存一个数据结构,称为页表(page table)。
- 页表的主要作用是为地址空间的每个虚拟页面保存地址转换(address translation),从而让我们知道每个页在物理内存中的位置。
- 这个页表是一个每进程的数据结构(我们讨论的大多数页表结构都是每进程的数据结构。
4、页号的地址转换:
虚拟页号,又称VPN,需要操作系统使用PFN(物理页号)进行转换,偏移量则不用,保持不变。
虚拟地址 = VPN + 偏移量
物理地址 = PFN + 偏移量
5、页表的具体表述:
页表就是一种数据结构,用于将虚拟地址(或者实际上,是虚拟页号)映射到物理地址(物理帧号)。
最简单的形式称为线性页表(linear page table),就是一个数组。操作系统通过虚拟页号(VPN)检索该数组,并在该索引处查找页表项(PTE),以便找到期望的物理帧号(PFN)。
6、PTE的部分内容:
- 有效位。通常用于指示特定地址转换是否有效。
- 保护位。表明页是否可以读取、写入或执行。
- 参考位。有时用于追踪页是否被访问,也用于确定哪些页很受欢迎,因此应该保留在内存中。
- 脏位。表明页面被带入内存后是否被修改过。
分页:快速地址转换(TLB)
1、TLB(地址转换缓存):就是频繁发生的虚拟到物理地址转换的硬件缓存(cache)。也称地址转换旁路缓冲存储器。
2、虚拟地址转换为为物理地址过程(复习一下):
虚拟地址 = VPN + 偏移量 ==>> 物理地址 = PFN + 偏移量
3、TLB硬件的基本算法:
首先从虚拟地址中提取页号(VPN)。然后检查TLB 是否有该VPN 的转换映射。接下来有两种情况:
- 如果有,我们有了TLB 命中。
- 如果CPU 没有在TLB 中找到转换映射(TLB 未命中)。则接下来硬件访问页表来寻找转换映射,并用该转换映射更新TLB。最后,当TLB 更新成功后,系统会重新尝试该指令,这时TLB 中有了这个转换映射,内存引用得到很快处理。
上述未命中系列操作开销较大,主要是因为访问页表需要额外的内存引用。
4、硬件缓存背后的思想是利用指令和数据引用的局部性(locality):
- 时间局部性:时间局部性是指,最近访问过的指令或数据项可能很快会再次访问。
- 空间局部性:空间局部性是指,当程序访问内存地址x 时,可能很快会访问邻近x 的内存。
5、一个区别:
- 从函数调用返回后,会继续执行此次调用之后的语句。
- 从TLB 未命中的陷阱返回后,硬件必须从导致陷阱的指令继续执行。
6、缓存替换(cache replacement):当TLB满了,插入新项,将替换旧项,常见的两种策略:
- 替换最近最少使用。尝试利用内存引用流中的局部性,假定最近没有用过的项,可能是好的换出候选项。
- 随机替换策略。
分页:较小的表
1、一个假设:
假设32位地址空间(即4GB内存大小),页大小为4KB,每个页表项为4字节。
==>> 则一个这样的地址空间中会有100w虚拟页面。
==>> 则每个页表大小为4MB左右。
==>> 一个进程一个页表。
假设100个进程同时运行,则需要400M大小的地址存页表。这,显然不合理。
2、简单的解决方案:增大页,比如页从4KB,增大到16KB,一个页表就减小到1M。
缺点:增大页,会导致更多的内部碎片。
3、混合方法(杂合方法):不为进程的整个地址空间提供单个页表,而是为每个逻辑分段提供一个。
4、二级页表方法: 增加一个“页目录”的新结构,将线性页表变成了类似树的结构。页目录项(PageDirectory Entries,PDE)。
基本思想(着重理解):首先,将页表分成页大小的单元。然后,如果整页的页表项(PTE)无效,就完全不分配该页的页表。为了追踪页表的页是否有效(以及如果有效,它在内存中的位置),使用了名为页目录(page directory)的新结构。页目录因此可以告诉你页表的页在哪里,或者页表的整个页不包含有效页。
缺点:在TLB命中时,性能和线性页表相同,在TLB 未命中时,需要从内存加载两次,才能从页表中获取正确的地址转换信息(一次用于页目录,另一次用于PTE 本身),而用线性页表只需要一次加载。
一旦从VPN 中提取了页目录索引(简称PDIndex),我们就可以通过简单的计算来找到页目录项(PDE)的地址:PDEAddr = PageDirBase +(PDIndex×sizeof(PDE))
这里就不展开了。
5、引申出的多级页表:
由于页目录可能也过大无法放入1页中,所以又引申出多级页表。
构建多级页表的目标:使页表的每一部分都能放入一个页。
6、其他想法:
- 反向页表
- 将页表交换到磁盘
注:
本站文章除注明转载/出处外,均为本站原创或翻译,转载前请务必署名,转载请标明出处。