OS内存管理

OS内存管理

      • 一、内存管理(核心:逻辑地址和物理地址的映射)
        • 1. 连续内存分配
        • 2. 非连续内存分配
          • 2.1. 段式
          • 2.2. 页式
          • 2.3. 段页式
      • 二、虚拟存储
        • 2.1 覆盖
        • 2.2 交换
        • 2.3 虚拟存储
        • 2.4 页面置换算法
        • 2.5 抖动

一、内存管理(核心:逻辑地址和物理地址的映射)

操作系统内存管理的目标

  1. 逻辑地址:启动后,OS逻辑划分物理内存。用户程序在运行的时候,只考虑逻辑地址,不用考虑物理地址。

    逻辑地址和物理地址的关系:CPU中ALU需要读取逻辑地址的内容,CPU中有个硬件MMU,MMU中有个地址映射关系表,负责转换逻辑地址和物理地址。CPU中的控制器把得到的物理地址和控制信号送到总线上,内存发送物理地址的内容给CPU。(操作系统做了什么等后面再补充)

  2. 保护:多个进程空间互不干扰

    地址安全检测:用OS有个表,执行前检查起始地址+访问长度是否超范围。确保每个进程访问的地址空间合法。

  3. 共享:进程可以访问相同内存

  4. 虚拟化:更多的地址空间

  5. 虚拟内存:内存不够用,将磁盘用于虚拟内存。

在操作系统中管理内存的不同方法

  • 重定位:链接后确定了代码相对地址,将程序.out载入内存,确定代码的逻辑地址。

  • 分段:代码、数据、堆栈分开存储

  • 分页:内存分成内存页4K,基础访问单位

  • 虚拟内存:按需分页虚拟内存

1. 连续内存分配

连续内存分配所涉及的问题:

  • 内存碎片问题:

    • 空闲内存无法利用,包括分配单元之间的未被分配的空闲内存,以及被分配了但未使用的内存。
  • 动态分区分配:

    • 包括分配连续区间来加载未运行的程序,以及分配区间给已运行的程序

    • 分配策略:

      ​ 需要维护的数据结构:所有进程被分配的分区,空闲分区

      • 最先匹配:找到第一个比要求的空间大的分区
      • 最佳适配:找比要求的空间大的最少的分区,根据空闲分区大小排序
      • 最差适配:找最大的,根据空闲分区大小排序
  • 碎片整理:

    • 调整进程占用的分区位置来减少或避免分区碎片
      • 压缩:条件:只能在进程等待状态下搬运,内存拷贝的开销需要另外考虑。
      • 交换式:把等待状态的进程放到虚拟内存上(硬盘),回收内存。

2. 非连续内存分配

连续内存分配存在碎片问题,而且动态分配内存修改困难。

非连续分配的目标:提高内存利用效率和管理灵活性,比如允许程序使用非连续的物理地址空间,允许共享代码和数据,支持动态加载和动态链接。(多个程序引用同一个库,这个库只导入一次)

非连续需要解决的问题:

  1. 逻辑地址和物理地址之间的转换。

    解决办法:软件实现(灵活、开销大),硬件实现(够用、开销小)

  2. 如何选择非连续分配中的内存分块大小

2.1. 段式

段式:分块大,要求每个段的段内物理地址连续,不同段可以放到不同的物理地址上

  • 段地址空间
    • 进程的段地址空间由多个段组成,分为主代码段、子模块代码段、公用库代码段、堆栈、堆数据、初始化数据、符号表等。段内用地址偏移访问,很少有段间访问。则连续的逻辑地址空间可以分为不连续的物理地址空间
  • 段访问机制
    • 逻辑地址由{ 段号+段内偏移 } 表示。访问过程:CPU根据逻辑地址,找到段号和段内偏移。在进程的段表中找到相应段号的段基址和长度。存储管理单元MMU判断是否越界(偏移<长度),然后根据段基址+偏移找到实际的物理地址。
2.2. 页式

页式:分块小,要求页内的物理地址连续,不同页可以放到其他地方

  • 帧Frame{ 帧号+偏移量 }:把物理地址划分为大小相同的基本分配单位。

  • 页Page{ 页号+偏移量 }:把逻辑地址划分为大小相同的基本分配单位。

    Frame和Page的大小要求相同,偏移量要求相同,页号和帧号可以不同。

  • 页表:{页号+帧号}:Frame和Page之间的转换关系。页表随进程运行动态变化。

访问过程:页表基址寄存器存放了页表的起始位置。CPU根据页号和偏移量,在在页表中找到对应的帧号,算出物理地址。页号可能没有对应的帧号,因此页表中还有标志位来表示映射关系是否存在。另外还有修改位和引用位,是否被修改,是否被访问。

​ 缺点:访问一个内存单源需要两次访问,另外,如果内存很大,页表也会很大。

​ 解决:

  • (快表TLB)可以通过缓存页表项,减少访问次数
  • (多级页表)对应逻辑地址,类似Page.x->Frame.y的映射。通过设置多级索引,减少页表存储空间。比如3级页表,逻辑地址用(p1,p2,p3,o)表示,p1指向第一级页表的页号,其中存放第二级页表的基址,p2指向第二季页表的页号,p2页号+基址=第三级页表的基址,p3页号+基址+偏移量o=物理地址位置。
  • (页寄存器、反置页表):根据物理页号映射逻辑页号,类似Frame.y->Page.x的映射。大小只和物理地址大小有关,和逻辑地址大小无关。省空间,可用哈希表做,但会有哈希冲突,加入PID可以缓解冲突,把结果反哈希算一下是否相等即可。
2.3. 段页式

在段式存储管理基础上,给每个段加一级页表,逻辑地址= { 段号+页号+偏移量}

在寄存器中找到段基址+段号=段表项,其中有页表的基址。页基址+页号=页表项,其中由帧号的基址。帧号+偏移量=物理地址。优点:便于实现内存共享。共享段指向同一个页表,通过相同的页表基址,实现内存共享

二、虚拟存储

需求:进程并发量大,导致内存不够用。要求在小内存中运行大程序

解决:在非连续存储的基础上,将部分内存中的内容放入外存

覆盖:应用程序手动(得自己写)把需要的指令和数据保存在内存中。

交换:操作系统自动(操作系统写)把暂时不执行的程序保存到外存中

虚拟存储:以页为单位自动装入更多更大的程序

2.1 覆盖

问题:一个程序的内存空间不够用

覆盖:将程序划分为若干功能相对独立的模块,将不同时执行且大小相近的模块共享一块内存区域。

换入换出的基本单位:程序内部的模块

具体:将程序划分为必选和可选项,必选部分常驻内存,可选部分在用时放入内存。

缺点:编程难度增加

2.2 交换

问题:并发情况下,正在运行的程序内存不够用

交换:将暂时不运行的程序放到外存。

换入换出的基本单位:整个不运行的程序的地址空间

换出之后再换入需要采用动态地址映射。

2.3 虚拟存储

例子:二维数组有从上到下和从左到右两种遍历方式。如果是从上到下,且数组特别大,按页存储,在访问的过程中会N次缺页,处理效率大大降低!

虚拟存储的目标:只把部分程序放入内存,就让程序运行。且操作系统自动完成

装载时:只将当前指令执行需要的部分页面或段装入内存

缺页/缺段中断:执行中需要的指令或数据不存在内存中。CPU通知OS调入相应页/段

保存:将内存中不用的页/段放入外存。注意:应能方便找到在外存的页。Linux专门设置了对换分区。另一种是采用特殊格式的文件来存储

实现方式:

  • 虚拟页式存储

    在页式存储管理的基础上,增加请求调页和置换算法。页表项增加了几个标志位:驻留位:判断该页是否在内存中;修改位:判断当前页是否被修改过,若修改过,置换时需要将修改的内容放到外存中,否则置换时直接作废即可;访问位:判断当前页是否被访问过,不常用的页需要被放入外存中。保护位:表示该页允许的访问方式:rwx。

  • 虚拟段式存储

2.4 页面置换算法

置换算法:缺页异常,需要调入新页而内存已满,就需要置换

要求:页面调入调出次数少,调出未来不用的页面(难点:如何估计?)

页面锁定:必须内容常驻内存,不可被置换

置换算法评价方法:记录进程访问内存的轨迹,模拟每种页面的置换行为,记录产生缺页的次数,越少性能越好

  • 局部置换算法:分配给进程的物理页面数确定,置换只局限在该进程占用的物理页面内

    • 最优算法:缺页时,计算内存中每个页的下一次访问时间,选择未来最长时间不访问的页面,但该算法无法实现,是用于评估置换算法。
    • 先进先出FIFO:选择在内存驻留时间最长的页面进行置换
    • 最近最久未使用算法LRU:选择最长时间没有被引用的页面
      • 改进:时钟算法CLOCK:只做粗略统计,各个页面组成环形链表,指针指向最先调入的页面,环形查找,访问过的留下,没访问过的被置换。
      • 改进:最不常用算法:每个页设置一个访问计数,访问时+1,缺页时,选择计数最小的页
  • 全局置换算法:全局置换算法位进程分配可变数目的物理页,选择范围是所有可置换的物理页面。

    CPU利用率和并发进程数的关系:进程数少,CPU利用率低,增加并发进程,导致内存访问增加,降低CPU利用率。当并发进程增加到一定数量,再增加会导致CPU利用率迅速降低。

    • 工作集算法

      • 工作集:假设当前时刻为t,时间窗口大小为α,一个进程在[ t-α,t]的时间段内,使用的逻辑页的集合。工作集随着时间不断变化。进程的不同阶段,对内存的需求都不同。当内存访问的局部区域位置稳定时,工作集稳定,当局部区域位置改变时,工作集快速扩张或收缩,过渡到下一个稳定值。

      • 常驻集:当前时刻进程实际驻留在内存中的页集合

      工作集是进程在运行过程中的固有性质。常驻集取决于系统分配给进程的物理页数量和页面置换算法。

      通过控制常驻集的大小,影响缺页率:若工作集是常驻集的子集,则缺页少;若工作集发生剧烈变动,则缺页多;进程常驻集大小到达一定数量,缺页率不会明显下降。

      • 工作集算法思路:设置内存访问链表,维护时间窗口α内的访问页面链表。访问内存时,换掉常驻集中,不在工作集中的页面。缺页时,换入页面。注意:区别于局部置换算法,该置换算法并不一定在缺页时才进行置换。
        OS内存管理_第1张图片
    • 缺页置换算法

      • 缺页率=缺页次数/内存访问次数,或缺页平均时间间隔的倒数。影响缺页率的因素:置换算法、物理页面数、页大小、编程方法等。

      • 进程的物理页数越多,缺页率越低。

      • 缺页置换算法思路:

        ​ 通过调整常驻集的大小,使每个进程的缺页率保持在一定范围内。若缺页率高于上限,增加常驻集以分配更多的物理页面数。若缺页率低于下限,CPU效率低,减少常驻集以减少物理页面数

        访存时,设置引用位标志(是否访问)。缺页时,计算从上次缺页时间间隔T = |t_last - t_now|。若 T > α(窗口大小),缺页率低,置换所有t_last到t_now时间间隔内没有被访问的页。若T <= α,缺页率高,增加缺失页到常驻集中。

OS内存管理_第2张图片

2.5 抖动

抖动:驻留内存的进程过多,导致进程物理页过少,不能包含工作集,造成大量缺页,频繁置换,运行速度慢。操作系统需要在并发和缺页率之间达到平衡。

你可能感兴趣的:(操作系统)