《现代操作系统》03章 存储管理(二)

0 前文

《现代操作系统》03章 存储管理(一)

3 虚拟内存

为什么需要虚拟内存呢?

这是软件发展带来的需求,软件功能越来越丰富导致体积越来越大,即使内存的空间也在不断增大但依然无法赶上软件的发展速度。这就带来了矛盾:怎样在有限的内存中运行多个大型应用程序?

3.1 简介

交换技术也仅仅对体积较小的程序有用,因为SATA硬盘的传输速率也非常的有限。

在早期解决大型软件运行的问题时(一般在工程和科研领域),程序员将程序分为多段——覆盖(【n】overlay),由操作系统根据运行需要将覆盖从硬盘读入内存。程序的分段枯燥、费时且容易出错。

在这样的发展背景下虚拟内存(Virtual Memory)应运而生:每个程序拥有自己的地址空间,地址空间被分为多个块——页(page),每个页有连续的地址范围,并且部分页被映射到物理内存,程序运行时若该page映射在物理内存则直接执行,若该page未映射在物理内存则由操作系统读取相应的page到物理内存并执行失败的代码。

虚拟内存特别适用于多道程序设计,在一个程序等待内存读入时可以交出CPU让其他程序运行。

虚拟地址(virtual address):由程序产生的地址,例如 MOV REG,1000中的1000就是一个虚拟地址

虚拟地址空间:由虚拟地址构成的地址空间

虚拟内存系统 与 无虚拟内存系统的区别


请添加图片描述


上图为虚拟内存系统,寻址命令会先经过MMU(Memory Management Unit)处理再送到地址总线完成寻址动作。无虚拟内存系统直接将地址送到地址总线。

有些系统中MMU集成如CPU内部,有些系统中MMU为单独的芯片

3.2 分页

3.2.1 page & page frame

分页的目的

一台16位的机器可以产生0-64KB的虚拟地址空间,若机器只装载了32KB的运行内存,若超过了32K的程序是无法一次性装入内存的,为了方便内存管理(虚拟与真实的映射),需要将内存分页,这与空闲内存管理的分块思想不谋而合,甚至可以说二者是相辅相成的。

分页

分页 是一种虚拟内存管理技术,该技术将虚拟内存的地址空间分为等长连续块。例如一个以4KB为页面大小的16位机器,其虚拟地址空间被分为0-4095、4096-8191、8192-12287…(以此类推)

页框

物理内存中与页面(page)对应的是页框(page frame),通常二者大小相同,常用大小为512byte-64KB,RAM与磁盘的交换是以整页为单位的。

3.2.2 MMU的工作机制

MMU

MMU的工作就是维护一张虚拟内存与物理内存的映射表——页表(page table),如执行 “MOV REG 0” ,MMU查表0-4096的page映射到8192-12287的page frame,因此MMU把8192送到了Address Bus,这条指令被转义为"MOV REG 8192" 。

对于page有没有page frame的映射,表中会用 present/absent bit来表示。

缺页中断

当page与page frame无映射关系时,MMU通过 缺页中断(page fault)使CPU陷入操作系统,操作系统找到一个使用频率低的page frame并将其写入磁盘(若磁盘内无该page frame的内容),然后把需要访问的page读入回收的page frame,修改MMU中的映射表,退出中断。

请添加图片描述


虚拟地址的前四位作为页表的索引,将索引送入页表搜索,检查映射情况,存在即进行组合输出并送至地址总线,不存在即陷入操作系统。

3.3 页表

虚拟地址与页表关系

虚拟地址由虚拟页号和偏移量构成,虚拟页号的位数和偏移量的位数共同决定了page的大小。虚拟页号作为页表的索引,在也表中搜寻对应的page frame number,页表可认为是一个以page number为输入,page frame number为输出的函数。

页表项的结构

页表项的结构与机器类型密切相关,但存储内容大致相同。32bit是页表项的常用大小。

请添加图片描述

区域 功能
保护位(protection bit) 指出该页允许何种类型访问(读/写/只读/只写等等)
修改位(dirty bit) 在写入一页时由硬件自动置位,在重新分配页框时。若此位为1(该页框被改写过,表示此页框是脏的),需要将页框内容写回磁盘(因磁盘中的副本已和页框内的不一致),若此位为0(该页框内容未被改写,表示此页框是干净的),内容无需写回磁盘,可直接丢弃
访问位 不论读写该位都被系统置位,帮助系统进行page淘汰决策
高速缓存禁止位 禁止页面被高速缓存,用于映射到寄存器的页面,寄存器中存储大量状态,系统和进程的状态是时刻变化的,高速缓存中存放的是相应内容的副本,若寄存器被高速缓存,实时性降低(具有独立IO空间而不使用内存映射的机器不需要此位)

注意 在缺页中断中,保存淘汰页面内容的磁盘地址不在MMU中,而是在操作系统的软件表格中
页表一般存储在内存中(每个进程都有自己的页表)


虚拟内存系统需要解决的问题:

-(1)虚拟地址到物理地址的映射必须非常快
每条指令要进行一两次或多次内存访问(若进程的页表存储在内存中),若查表时间过长将影响运行速度
-(2)虚拟空间的增大带来页表的增大
现代计算机多为32bit或64bit的虚拟地址,以4KB为页长,32bit虚拟空间有100,0000页,64bit虚拟空间超乎想象


3.4 加速分页过程

两种极端的设计思路

(1)设计一组“快速硬件存储器”用于存放进程页表副本,之后就不必再访问内存。缺点是成本高、上下文切换要重装页表,性能降低
(2)仅用一个寄存器存放进程页表的起始位置,每条指令都要一次或多次内存访问,速度慢

3.4.1 转换检测缓冲区(TLB)

这种设计思路首先基于一种现象:

大多数程序对 少量 页面 多次 访问

转换检测缓冲区(Translation Lookaside Buffer)

别名:相联存储器
位置:通常位于MMU
表项数量:通常不超过64
表项信息:虚拟页号、修改位、保护位、对应页框号、有效位


应用举例:

进程循环代码虚拟页号:19、20、21
数组地址虚拟页号:129、130
数组计算索引虚拟页号:140
堆栈虚拟页号:860、861

TLB加速分页内容:

有效位 虚拟页号 修改位 保护位 页框号
1 140 1 RW 31
1 20 0 R X 38
1 130 1 RW 29
1 129 1 RW 62
1 19 0 R X 50
1 21 0 R X 45
1 860 1 RW 14
1 861 1 RW 75

TLB工作过程:

请添加图片描述

注意 匹配不成功淘汰表项时,将其修改位复制到内存的页表项中,访问位置位,其余位不改变
页表项从页表装入TLB时,所有的值都从内存复制


3.4.2 软件TLB管理

为何用软件管理

对于TLB的管理和TLB失效处理可以选择由MMU的硬件来完成,也可以使用软件(操作系统)来完成。现在的主流机器大多使用软件管理TLB,当TLB访问失效时产生一个TLB失效并交给操作系统来处理,TLB失效处理应在几条指令间完成,因为TLB的失效较为频繁。这样简化了MMU的设计,为改善机器性能的设计留出空间。

TLB管理策略

其中一种策略是预判即将被访问的页并将其加入到TLB中;还有一种是在内存中维护一个较大的软TLB(该页面常驻硬TLB),操作系统先检索软TLB再检索硬TLB,有效减小TLB失效。

硬失效与软失效

软失效:访问页面不在TLB中,在内存页表中
硬失效:访问页面在TLB与内存页表中均没有,需要磁盘IO

3.5 针对大内存的页表

3.5.1 多级页表

概念:可以类比为网络中的IP地址,IPv4的地址也分为多级
例如把32位地址分为10位PT1域、10位PT2域和12位Offset(偏移)域,页面长度位4KB,共2^20个页面

目的:避免把没用的页表一直存储在内存中,如需要12MB内存的进程,底端4MB程序,之后是4MB数据,顶部是4MB堆栈,中间均为空闲区(不需要存储这些页表)

举例

按照上面提到的参数假设,32bit=4GB,PT1将4GB分为4MB的1024份,PT2的一个页表将4MB分为4KB的1024份
现在要访问 0x00403004(0000000001 0000000011 000000000100)

请添加图片描述

这样,在这个例子中内存中仅需要存放4张页表就可以满足该进程的需求,在PT1页表中,没有使用的表项present/absent bit全都置0即可,若该进程访问这些表项会引起缺页中断,操作系统将根据情况处理。

PT1、PT2、Offset位数可以自由设计,当级数超过3级复杂度也随之升高,超过三级的设计价值还有待研究。

为什么使用倒排表

对于64位机器,多级页表也显得力不从心了,需要更好的解决之道。若64位机器以4KB为页面大小,需要一个有2^52表项的页表,若一个表项为8byte,整个页表要用3000wGB,即使使用多级页表,占用的空间也是相当惊人的(指数函数的增长速度永远都不会让人失望)

概念

倒排表是一种逆向思维,原先是有多少虚拟空间就要对应有多少表项,倒排则是根据RAM的大小设计表项的多少,即每一个页框有一个表项。例如64bit虚拟空间,4KB的page,1GB的RAM,只需要262144个页表项,表项记录哪一个虚拟页面或进程对应该页框。

问题

从虚拟地址到物理地址的转换变得困难,虚拟地址不在具有页表内的索引功能(页表的排序是按照页框顺序排的),必须搜索整个页表才能得到结果,并且每一次内存访问都要执行一次,这又降低了效率。

解决

使用TLB:将频繁使用的表项放入TLB,并维护TLB表,TLB失效时再搜索全表
使用哈希表(散列表):将虚拟地址作为key,设计哈希函数(散列函数),将表项存储在哈希表(散列表)中,当散列表槽数和页框数相等,散列表冲突链平均长度为1,效率很高(哈希表的知识之后专写一篇博客讲述)

请添加图片描述

倒排表在64bit机器中很常见,其他处理大虚拟内存方法参见Tallurl等人的论文(1995)

X 往期文章

《现代操作系统》03章 存储管理(一)

《现代操作系统》02章 进程与线程(三)

今天,我是数据库的BOS(读者-写者问题)

哲学家不会吃饭了,我们快来帮帮他们(C语言、进程通信)

《现代操作系统》02章 进程与线程(二)

《现代操作系统》02章 进程与线程(一)

《现代操作系统》01章 基本概念

Python+OpenCV+imutils的简单图片处理(放缩、翻转、旋转、灰度RGB提取)

python手写K-means实现二维聚类.


如果文中有误,还请在评论区指正。这里是海小皮,我们一同进步!!!

Guess you like

Origin blog.csdn.net/weixin_42464904/article/details/119977300