计算机操作系统--内存管理

内存

内存基础

内存是用于存放数据的硬件。程序执行前需要先放在内存中才能被CPU处理。

逻辑地址 vs 物理地址

程序运行过程:

编译:由编译程序将用户源代码编译成若干个目标模块(编译就是把高级语言翻译为机器语言);

链接:由链接程序将编译后形成的一组目标模块,以及所需库函数链接在一起,形成一个完整的装入模块;

装入(装载):由装入程序将装入模块装入内存运行。

三种装入方式:

  1. 绝对装入:编译时产生绝对地址;
  2. 可重定向装入(静态重定位):装入时逻辑地址转换为物理地址;
  3. 动态运行时装入(动态重定位):运行时逻辑地址转换为物理地址,需设置重定向寄存器,是现代操作系统采取的方式。

内存管理的概念

内存空间的分配与回收

内存空间的扩种(实现虚拟性)

地址转换:操作系统负责实现逻辑地址到物理地址的转换(三种方式)

存储保护:

  • 设置上下限寄存器;
  • 利用重定位寄存器、界地址寄存器进行判断。

覆盖与交换技术

用于内存空间的扩充。

覆盖技术的思想:将程序分为多个段(多个模块)常用的段常驻内存,不常用的段在需要时调入内存。

内存中分为一个“固定区”和若干个“覆盖区”。需要常驻内存的段放在“固定区”中,调入后就不再调出(除非运行结束)不常用的段放在“覆盖区”,需要用到时调入内存,用不到时调出内存。

但由于必须由程序员声明,对用户不透明,因此已不再使用

交换技术的设计思想:内存紧张时,系统将内存中某些进程暂时换出外村,把外存中某些已具备运行条件的进程换入内存,中级调度就是决定哪个处于挂起状态的进程重新调入内存。

具有对换功能的操作系统中,通常把磁盘空间分为文件区对换区两部分。文件区主要用于存放文件,主要追求存储空间的利用率,因此对文件区空间的管理采用离散分配方式;对换区空间只占磁盘空间的小部分,被换出的进程数据就存放在对换区。由于对换的速度直接影响到系统的整体速度,因此对换区空间的管理主要追求换入换出速度,因此通常对换区采用连续分配方式。总之,对换区的I/O速度比文件区的更快。

连续分配管理方式

内部碎片:分配给某进程的内存区域中,有些部分没有用上;

外部碎片:指内存中的某些空闲分区由于太小而难以利用。

单一连续分配

在单一连续分配方式中,内存被分为系统区和用户区

系统区通常位于内存的低地址部分,用于存放操作系统相关数据;用户区用于存放用户进程相关数据。

内存中只能有一道用户程序,用户程序独占整个用户区 空间。

储存利用率极低,有内部碎片,无外部碎片。

固定分区分配

20世纪60年代出现了支持多道程序的系统,为了能在内 存中装入多道程序,且这些程序之间又不会相互干扰,于是将整个用户空间划分为若干个固定大小的分区,在每个分区中只装入一道作业,这样就形成了最早的、最简单的一种可运行多道程序的内存管理方式。

操作系统需要建立一个数据结构一一分区说明表,来实现各个分区的分配与回收。每个表项对应一个分区,通常按分区大小排列。每个表项包括对应分区的大小、起始地址、状态(是否己分配)

有内部碎片,无外部碎片。

动态分区分配

动态分区分分配又称为可变分区分配。这种分配方式不会预先划分内存分区,而是在进程装入内存时,根据进程的大小动态地建立分区,并使分区的大小正好适合进程的需要。因此系统分区的大小和数目是可变的。

如果内存中空闲空间的总和本来可以满足某进程的要求,但由于进程需要的是一整块连续的内存空间,因此这些 “碎片”不能满足进程的需求。可以通过紧凑(拼凑,Compaction)技术来解决外部碎片。

无内部碎片,有外部碎片。

动态分区分配算法(四种):解决的是当有多个分区都能满足内存要求是,选择哪个分区。

非连续分配管理方式

基本分页存储

基本分页存储管理的思想:把内存分为一个个相等的小分区(页框),再按照分区大小把进程拆分成一个个大小相等的小部分(页、页面)。操作系统以页框为单位为各个进程分配内存空间。进程的每个页面分别放入一个页框中。也就是说,进程的页面与内存的页框有一一对应的关系。各个页面不必连续存放,也不必按先后顺序来,可以放到不相 邻的各个页框中。

物理地址与逻辑地址的转换:

  1. 算出逻辑地址对应的页号
  2. 找到该页号对应页面在内存中的起始地址(页表实现
  3. 算出逻辑地址在页面内的偏移量
  4. 物理地址 = 页面始址 + 页面偏移量

内存管理单元(MMU)管理着地址空间和物理内存的转换,其中的页表(Page table)存储着页(程序地址空间)和页框(物理内存空间)的映射表。

一个虚拟地址分成两个部分,一部分存储页面号,一部分存储偏移量。

下图的页表存放着 16 个页,这 16 个页需要用 4 个比特位来进行索引定位。例如对于虚拟地址(0010 000000000100),前 4 位是存储页面号 2,读取表项内容为(110 1),页表项最后一位表示是否存在于内存中,1 表示存在。后 12 位存储偏移量。这个页对应的页框的地址为 (110 000000000100)。

具有快表的地址变换机构

时间局限性:如果执行了程序中的某条指令,那么不久后这条指令很可能被再次执行;如果某个数据被访问过,不久之后该数据很可能再次被访问(因为程序中有大量循环)。

空间局限性:一旦程序访问了某个储存单元,在不久之后,其附近的储存单元也可能被访问。

由于局部性原理,可能连续很多次查到的都是一个页表项。这时可以引入快表,块表又称联想寄存器(TLB),是一种访问速度比内存快很多的高速缓冲存储器。这样在访问页表前先访问快表,若未命中,再访问页表。

两级页表

单级页表存在的问题:

  • 页表必须连续存放,因此当页表很大时,需要占据很多个连续的页框
  • 没有必要让整个页表常驻内存,因为进程在一段时间内可能只需要访问某几个特定的页面。

可以把必须连续存放的页表再分页,再建立一个页表的页表,称之为页目录表或外层页表或顶层页表。

步骤

  1. 按照地址结构将逻辑地址拆分成三部分;
  2. 从PCB中读出页目录表始址,再根据一级页号查页目录表,找到下一级页表在内存中的存放位置;
  3. 根据二级页号查表,找到最终想访问的内存块号;
  4. 结合页内偏移量得到物理地址。

注:各级页表的大小不能超过一个页面,若两级页表不够,可以分更多级。

基本分段存储

按照程序自身的逻辑关系划分为若干个段,每个段从0开始编制,以段为单位进行分配,每个段在内存中占据连续空间,但各段之间可以不相邻。通过段号查询段表来确定物理地址。

分页和分段的比较:

  • 对程序员的透明性:分页透明,但是分段需要程序员显式划分每个段。
  • 地址空间的维度:分页是一维地址空间,分段是二维的。
  • 大小是否可以改变:页的大小不可变,段的大小可以动态改变。
  • 出现的原因:分页主要用于实现虚拟内存,从而获得更大的地址空间;分段主要是为了使程序和数据可以被划分为逻辑上独立的地址空间并且有助于共享和保护

段页式存储

程序的地址空间划分成多个拥有独立地址空间的段,每个段上的地址空间划分成大小相同的页。这样既拥有分段系统的共享和保护,又拥有分页系统的虚拟内存功能。

虚拟存储技术

传统存储管理方式的缺点:

  • 一次性:作业必须一次性全部装入内存后才能开始运行,大作业无法运行;
  • 驻留性:一旦作业被装入内存,就会一直驻留在内存中。

基于局部性原理,在程序装入时,可以将程序中很快会用到的部分装入内存,暂时用不到的部分留在外存,就可以让程序开始执行。
在程序执行过程中,当所访问的信息不在内存时,由操作系统负贵将所需信息从外存调入内存(请求调页),然后继续执行程序。若内存空间不够,由操作系统负责将内存中暂时用不到的信息换出到外存(页面置换)。在操作系统的管理下,在用户看来似乎有一个比实际 内存大得多的内存,这就是虚拟内存

请求分页管理

关键点:

  • 页表机制
  • 缺页中断机制
  • 地址变换机制

页表项相对于基本分页存储多了一些状态项:

在请求分页系统中,每当要访问的页面不在内存时,便产生一个缺页中断,然后由操作系统的缺页中断处理程序处理中断。此时缺页的进程阻塞,放入阻塞队列,调页完成后再将其唤醒,放回就绪队列。如果内存中有空闲块,则为进程分配一个空闲块,将所缺页而装入该块,并修改页表中相应的页表项。若内存空间不够,由操作系统负责将内存中暂时不用的信息换出到外存。

页面置换算法

在程序运行过程中,如果要访问的页面不在内存中,就发生缺页中断从而将该页调入内存中。此时如果内存已无空闲空间,系统必须从内存中调出一个页面到磁盘对换区中来腾出空间。

页面置换算法和缓存淘汰策略类似,可以将内存看成磁盘的缓存。在缓存系统中,缓存的大小有限,当有新的缓存到达时,需要淘汰一部分已经存在的缓存,这样才有空间存放新的缓存数据。

页面置换算法的主要目标是使页面置换频率最低(也可以说缺页率最低)。

最佳置换算法

OPT, Optimal replacement algorithm

所选择的被换出的页面将是最长时间内不再被访问,通常可以保证获得最低的缺页率。

是一种理论上的算法,因为无法知道一个页面多长时间不再被访问。

举例:一个系统为某进程分配了三个物理块,并有如下页面引用序列:

7,0,1,2,0,3,0,4,2,3,0,3,2,1,2,0,1,7,0,1

开始运行时,先将 7, 0, 1 三个页面装入内存。当进程要访问页面 2 时,产生缺页中断,会将页面 7 换出,因为页面 7 再次被访问的时间最长。

最近最久未使用

LRU, Least Recently Used

虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。

为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。

因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。

4,7,0,7,1,0,1,2,1,2,6

最近未使用

NRU, Not Recently Used

每个页面都有两个状态位:R 与 M,当页面被访问时设置页面的 R=1,当页面被修改时设置 M=1。其中 R 位会定时被清零。可以将页面分成以下四类:

  • R=0,M=0
  • R=0,M=1
  • R=1,M=0
  • R=1,M=1

当发生缺页中断时,NRU 算法随机地从类编号最小的非空类中挑选一个页面将它换出。

NRU 优先换出已经被修改的脏页面(R=0,M=1),而不是被频繁使用的干净页面(R=1,M=0)。

先进先出

FIFO, First In First Out

选择换出的页面是最先进入的页面。

该算法会将那些经常被访问的页面也被换出,从而使缺页率升高。

第二次机会算法

FIFO 算法可能会把经常使用的页面置换出去,为了避免这一问题,对该算法做一个简单的修改:

当页面被访问 (读或写) 时设置该页面的 R 位为 1。需要替换的时候,检查最老页面的 R 位。如果 R 位是 0,那么这个页面既老又没有被使用,可以立刻置换掉;如果是 1,就将 R 位清 0,并把该页面放到链表的尾端,修改它的装入时间使它就像刚装入的一样,然后继续从链表的头部开始搜索。

时钟

Clock

第二次机会算法需要在链表中移动页面,降低了效率。时钟算法使用环形链表将页面连接起来,再使用一个指针指向最老的页面。

猜你喜欢

转载自blog.csdn.net/TJtulong/article/details/99447694