操作系统如何进行内存管理

物理内存管理

物理内存有四个层次,分别为:
寄存器:速度最快,存储空间少,价格贵
高速缓存:次之
主存:再次之
磁盘:速度最慢,存储空间最多,价格便宜
操作系统通过内存管理器对物理内存进行管理,主要工作是记录哪些内存是正在使用的,在进程需要时分配内存以及在进程完成时回收内存。

地址生成过程

内部碎片和外部碎片:

  • 内碎片:固定分区法产生,指被占用分区上未被利用的空间,由于该分区已被占用,无法被分配使用
  • 外碎片:动态分区法产生,指被占用分区之间的小空间,虽可利用,但实际通常由于太小而无法被分配

内存分配技术及其优缺点

  1. 等长固定分区法:每个分区大小相同,在系统启动时分配完毕,且运行期间保持不变;每次给进程分配一整块区域,因此进程大小必须不大于分区的大小
    • 优点:系统维护管理信息少,只需一个固定行数的表格,记载分区使用情况;内存分配算法简单
    • 缺点:不同进程需要空间不同,内碎片多,浪费空间;分区总数固定,限制并发执行的程序数量
  2. 不等长固定分区法:与上不同点在于分配时根据进程的大小在空闲分区选择一个大小合适的分区,在系统启动时分配完毕,且运行期间保持不变;每个进程的分区可不等长。优缺点同上。
  3. 动态分区法:在系统运行中,根据每个进程需要的空间大小确定分区大小;通过空闲分区链表进行组织
    • 优点:并发执行程序数量不受限制,只取决于是否有大小合适的内存块可以分配
    • 缺点:管理空闲块的复杂度增加;分配算法的时间开销增加,可能需遍历多次才能找到合适的内存块
  4. 页式内存管理:把固定分区面积缩小,一个进程可以使用多个分区;进程被分割为若干块,装入内存中的几个分区中,物理上无需相连,逻辑上通过页表关联。为内存不连续分配方法。
    • 优点:不存在任何外部碎片,只在每个进程的最后一个页中存在内部碎片
  5. 段式内存管理:按照逻辑意义将程序分为若干个段,每个段独立载入到内存的不同区间中
    • 优点:分页不考虑每个页内容的意义;分段按照逻辑关系划分
    • 缺点:每个段必须连续,全部加载到内存中
  6. 段页式内存管理:把分段和分页两种方式结合,先把程序按逻辑意义分成段,然后每个段分成固定大小的页

连续内存分配之动态分区分配算法及优缺点

  1. 最先匹配算法
    • 原理:空闲分区列表按地址顺序排序;分配过程中,搜索一个合适的分区;释放分区时,检查是否可与临近的空闲分区合并
    • 优点:简单;在高地址空间有大块的空闲分区
    • 缺点:存在外部碎片;分配大块时较慢;每次查找均从低址部分开始,增加开销
  2. 最佳匹配算法
    • 原理:空闲分区列表按大小排序;分配时,查找一个合适的分区;释放时,查找并合并临近的空闲分区
    • 优点:适合分配尺寸较小的进程(可避免大的空闲分区被拆分;可减小外部碎片的大小;相对简单)
    • 缺点:外部碎片;释放分区较慢;容易产生较多无用小碎片
  3. 最差匹配算法
    • 原理:空闲分区列表按由大到小排序;分配时,选最大的分区;释放时,检查是否可与临近的空闲分区合并,进行可能的合并,并调整空闲分区列表顺序
    • 优点:中等大小的分配较多时,效果最好;避免出现太多的小碎片
    • 缺点:释放分区较慢;外部碎片;容易破坏大的空闲分区,后续难以分配大分区
  4. 下一个匹配算法
    • 原理:由于上述算法每次都需从头检查空闲分区,浪费时间。因此下一个匹配算法就是操作系统记住接下来该检查的空闲分区的位置,给进程分配分区时,系统从记录的分区开始依次向后查找直到遇到能用的分区为止,若到链表尾还未找到就从头开始
    • 缺点:上面三种算法或是留下大区间(最先,最佳),或是留下小区间(最差)。下一个匹配算法很难剩下面积很大的区间,会使剩余区间的大小较平均

虚拟内存管理

操作系统为每一个进程分配一个独立的地址空间,这个地址空间是逻辑地址,称为虚拟内存。虚拟内存与物理内存存在映射关系,通过页表寻址完成虚拟地址和物理地址的转换。

虚拟地址空间被分割为多个块,每个块称为一个页或者页面;物理内存被分成和页面大小相同的多个区域,称为页框;程序在加载时,可将任何一个页面放入物理内存中的任何一个页框,然后由CPU硬件负责将虚拟地址映射到物理内存的地址。

程序的整个地址空间无需全部载入物理内存,可以有部分暂时存储在外存,等到需要时再换入内存;若程序引用到一部分不在物理内存中的虚拟地址时,就会发生缺页中断,由操作系统负责将缺失的页面加载到页框中,并重新执行失败的指令。

Linux Swap空间

Swap空间可以是磁盘的一个分区,也可以是一个文件。它有两个用途:

  1. 将虚拟内存扩大到超过已安装的物理内存的容量
  2. 用于suspend-to-disk支持
    当内存不足时,操作系统先把内存中暂时不用的数据,存到磁盘的swap空间,释放内存空间

虚拟地址映射

页表:每个进程均有一个页表,描述该进程每个页面对应的页框号,以及该页面是否被载入内存(bit位)。

  • 页表表项包括的内容:
    • 页框号
    • 存在位:页面是否在内存
    • 访问位:页面是否已经被访问
    • 修改位:页面是否被修改,修改过的需重新写回外存
    • 页面号:在页表中的下标

进程在运行时,需要将页表载入内存。但在虚拟地址空间很大的情况下,页表会被分成很多个页面,那么进程的页表将占据很大的内存空间,甚至无法全部载入内存,所以就出现了一些针对大内存的页表的实现方法:

  1. 多级页表:将页表进一步分页,页目录表相当于“页表的页表”,记录每个内层页表放在哪个页框中;内层页表依然记录进程的每个页面存放在哪个页框中。

  1. 倒排页表:不再为每个进程记录到页框的映射,而是记录每个页框对应的(进程号,页面号)二元组。整个操作系统只需要一个倒排页表,节省了大量空间。但是它必须遍历整个页表才能找到某个表项,无法将页面号当作索引直接找到页框号。

  1. 散列表:为了节省页表空间,同时加速查找过程,可以将当前进程所有在内存中的页面建立一张散列表。用每个页面的虚拟地址来散列,相同散列值的元素被链接到一起,每个元素包括三项内容(页面号,页框号,指向链表中下一个元素的指针)。

TLB的原理

现代操作系统中,页表的个数很多,而每次执行语句时都要先查找页表,将虚拟地址转换为物理内存地址。这部分切换的时间开销很大。解决这个问题的方案就是为计算机设置一个小型的硬件设备TLB。

转换检测缓冲区(TLB),是MMU(内存管理单元)的一部分。它提供了一个缓冲区,记录虚拟页面号到物理页框号的映射,这样可在O(1)时间将虚拟页面映射到物理页框,无需访问页表。

工作流程:若页面号存在TLB中,直接得到页框号,访问内存;否则,从内存中的页表中得到页框号,将其存入TLB,访问内存。

TLB基于局部性原理实现:

  • 空间局部性:若程序访问了地址x,那么很有可能访问x附近的地址。
  • 时间局部性:若程序访问了地址x,那么很有可能立刻又访问x。

缺页中断

应用程序访问未加载到内存中的页面时,会引起缺页中断。操作系统将缺失的页面加载到页框中,然后重新执行引起异常的指令。(更准确的说应为缺页异常:软中断,中断为外部硬件产生的事件:硬中断)。

页面淘汰

当内存空间已被占满又要调入新的页面时,必须将已在内存中的某个页面淘汰掉。若被淘汰的页面曾经被修改过,还要将此页写回到外存,再换进新的页面。这一过程就叫做页面淘汰。

若某个页面频繁的被”调入-淘汰-调入-淘汰”,这种现象被称为抖动。抖动导致系统大部分时间花在页面置换上,因此在淘汰时,要选择今后不会或者最近不会用到的内容,以减少抖动。

页面置换算法及其适用场景

  1. 最佳置换算法(OPT):选择以后再也不会用到的页面淘汰;如果都会用到,就选择那些再次使用的时间距离现在最远的页面淘汰。这是一种理想情况下的页面置换算法,实际不可能实现。可作为评测其它淘汰策略的标准。
  2. 先进先出置换算法(FIFO):直接换出最早装入内存的页面。
    • 优点:简单
    • 缺点:性能不好,因为淘汰的可能是常用的页面
    • 适用场景:数据只用一次,将来不太可能使用;[redis]对数据的时效性有要求
  3. 第二次机会置换算法(SCR):对FIFO算法的改进,每个页面访问两次以后再淘汰。具体实现为设置页面访问位,每次检查队首的页面访问位(若该位为0,淘汰该页;该位为1,将该位置为0,将其移动到队尾,视为新装入的页)。
    • 优点:在一定程度避免经常使用的页面置换出去
  4. 时钟置换算法(Clock):对第二次机会置换法的改进。前者需要在链表中移动页面,而时钟置换算法将页面保存在环形链表中,只需要后移队头指针,就相当于把原队头放到队尾。
    • 优点:避免了移动链表节点的开销
  5. 最近最少使用算法(LRU):优先淘汰最久未被访问的页面。根据局部性原理,一个进程在一段时间内要访问的指令和数据都集中在一起。若一个页面很久没有被访问,那么将来被访问的可能性也比较小。
    • 优点:性能较好,能够降低置换频率
    • 缺点:存在缓存污染问题,即由于偶发性或周期性的冷数据批量查询,热点数据被挤出,导致缓存命中率下降
    • 适用场景:访问分布未知的情况;[redis]要求热点数据有效;应用对缓存的访问符合二八定律
  6. LRU- K:该算法核心思想是将“最近使用过1次”的判断标准拓展为“最近使用过K次”,LRU为LRU-1.
    • 优点:能够降低缓存污染的问题
  7. 最近最不经常使用算法(LFU):优先淘汰最近访问频率最少的页面。
    • 优点:避免缓存污染问题对LRU的命中影响
    • 缺点:存在访问模式问题,即若访问内容发生较大变化,LFU需要用更长的时间来适应,导致缓存命中率下降;维护相关数据结构开销大
    • 适用场景:数据的访问模式固定
  8. 随机淘汰法(Random)
    • 优点:实现简单,不需要保留有关访问历史记录的任何信息
    • 适用场景:若应用对于缓存key的访问概率相等,则可用此算法

操作系统一般最常用的就是LRU算法;一般数据的访问模式也是随时间变化的,所以大多数缓存也都是LRU算法或其变种。

虚拟地址空间组成

用户空间:

  1. 代码段.text:存放程序执行代码的一块内存区域。只读,代码段头部还会包含一些只读的常量。
  2. 数据段.data:存放程序已初始化的全局变量和静态变量的一块内存区域。
  3. BSS段.bss:存放程序中未初始化的全局变量和静态变量的一块内存区域。
  4. 可执行程序运行时多出两个区域:堆区和栈区。
    • 堆区:操作系统malloc动态申请内存。从低地址向高地址增长,连续空间。(开辟空间小于128K时,malloc底层调用brk()函数;大于128K,调用mmap())。—-malloc采用内存池管理方式,以减少内存碎片。具体实现为先申请大块内存作为堆区,然后将堆区分为多个内存块。当用户申请内存时,直接从堆区分配一块合适的内存块。采用隐式链表将所有空闲块联接,每个空闲块记录一个未分配的,连续的内存地址。
    • 栈区:存储局部变量,函数参数值。从高地址向低地址增长,连续空间。
  5. 文件映射区:位于堆与栈之间。(mmap)
    内核空间:DMA区,常规区,高位区。
posted @ 2023-03-01 16:26  yytarget  阅读(342)  评论(0编辑  收藏  举报