操作系统总结(八)内存管理

背景知识

  1. 为了使程序可以在内存正确执行需要对其出现的地址进行修改(重定位),重定位有三次机会,包括编译连接时进行(代码只能放到固定的位置)、在载入内存中进行(一旦载入内存代码无法移动)以及在程序执行过程中进行。其中最后一种是最合适的重定位机会。这样对后续的内存管理有极大的好处。
  2. 引入交换(swap)的概念,能够让更多的进程并发执行。即随着进程的执行,当进程在不同的运行状态下需要对其在内存和磁盘中进行换入换出操作。
  3. 运行时进行重定位可以实现进程之间的数据保护,即不同进程之间不能破坏其他进程的数据。
  4. 载入内存后程序使用逻辑地址,逻辑地址和运行物理地址之间需要地址转换。
  5. 虚拟地址:段+偏移
  6. 逻辑地址:虚拟地址中的偏移(实际应用中该地址和虚拟地址不加区分)
  7. 物理地址:物理内存中的实际地址
  8. 逻辑地址空间:逻辑地址的集合
  9. 线性地址空间:CPU地址总线可以访问的所有的地址的集合
  10. 物理地址空间:实际可访问的物理地址的集合
  11. 地址映射过程:逻辑地址->线性地址->物理地址
  12. 基地址:段或者页的首地址
  13. 偏移量:相对于基地址的地址数值

连续内存分配

对于一块连续的内存我们可以采用如下的方式将其分配给不同的进程:

  1. 固定分区-等长分区:每一个进程分给同样大小的内存(有的进程需要更多的内存,有的不需要这么多)
  2. 固定分区-变长分区:初始将分区分为大小不同的多个内存区,将较为合适的分给相应的进程。(不合理,还是分多大和浪费的问题)
  3. 可变分区:分区的大小随着进程的需求可以改变,根据进程的需求进行分割。
    • 怎样找到合适的分区位置:最佳适配(需要扫描所有分区,会产生许多小的空闲分区)、首次匹配(速度快)、最差匹配(扫描所有的分区,太慢;产生的空闲分区比较大)
    • 碎片的问题如何解决?(碎片:内存中剩余的无法使用的空间;内部碎片:分配给进程的内存,其他进程不能使用,但是这部分内存可能该进程并不使用;外部碎片:随着进程的不断装入装出,对分区的不断切割产生碎片)
    • 对外部碎片的解决办法:内存紧缩,即将空闲的内存移动到一起(效率太低,内存速度比CPU差很多,不合适)
    • 初始的请求内存的大小如何确定?程序的代码段和数据段不变,但是堆和栈是动态变化的,该怎么做。(分段管理)

分段内存管理

因为连续内存分配中的一些难以解决的问题,引出了分段管理内存。

对于一段代码,分为了数据段、代码段、、、,因此程序中的地址为段基地址+偏移。引入段内存管理将一维地址空间变为了二维。各个段可以分散放入内存中。对于每一个进程来说,都需要记录多个段的基地址(代码段、数据段等等),使用分段管理内存,仍然需要有内存分区表、内存分配算法。对于分段管理内存,地址翻译首先从段表获得段的基地址,然后和段的偏移相加,然后判断地址合法性,便获得了真实的物理地址。当进程切换时,段表也需要切换。

优点:不同的段有不同的含义可以区别对待,每一个段的地址独立,易于编程实现。

缺点:需要空间预留,空间很大却不能分配,即有大的内部碎片。还会产生外部碎片。空间利用低效。

分页内存管理

将内存分为小的页(4K),用一点分配一点,不会有外部碎片,内部碎片有上界。分页的内存管理需要页表数据结构的支持,即用户的虚拟地址在页表中通过页号获得内存的帧号,根据页内偏移,获得真实的物理地址。

问题

  • 页表可能很大,而每一条指令都需要多次查询页表,查询效率需要速率支持:页号连续,折半查找。

多级页表:

2的20次幂个页表项,每个4字节,都放在内存,要4M内存,系统同时并发10个进程,就需要40M的内存来保存页表,但是大部分页表中的逻辑地址都用不到。因此引入多级页表,顶级页表常驻内存,不需要映射的逻辑地址不需要建立页表项。32位逻辑地址格式(多级页表):页目录号、页表号、页内偏移。从页目录中获得页表的地址,根据页表号得到页框,根据偏移得到真实的物理地址。

缺点:多级页表使内存翻译速度更低因此需要提高速率。

怎样提高速率:增加硬件的支持TLB:首先到TLB中寻找页号,没有命中才到页表中查询。(TLB价格昂贵,因此比较小,但是根据程序局部性原理,其命中率很高,因此可以提高速度。TLB表的内容动态变化。(未命中,装入,TLB已经满了,替换一个,进程切换后,flush TLB)

分页管理的优缺点:

优点:靠近硬件,结构严格,高效使用内存。缺点:不符合程序员思考习惯。

段页结合内存管理

让段面向用户,页面向硬件

实现机理:程序的段划分的是线性地址空间(如0-4G),线性地址空间和内存被分割大小相等的片(页和页框),进程用页表建立页和页框的映射,进程创建申请段(线性地址空间),段申请页(物理内存),逻辑地址通过段表加页表算出物理地址,到达内存,进程切换时,段表和页表都跟着切换。优点:符合程序员习惯,并可高效利用内存,缺点:复杂,访问一次地址需要查表好多次。

段页结合的例子X86:

概念:

实模式,内存地址20位,1M。保护模式,地址32位,4G。

保护模式开启分页机制;实模式和保护模式分段管理有区别;实模式段寄存器中存储段基址;保护模式段选择器存储段描述符表中的索引;

实模式称为:段寄存器(CS,DS,ES,SS),保护模式称为:段选择器(6个)。

对于段选择器(段选择子):D3-D15位是索引值,D0-D1位是优先级(RPL)用于特权检查,D2位是描述符表引用指示位TI;TI=0指示从全局描述表GDT中读取描述符,TI=1指示从局部描述符中LDT中读取描述符。

GDT:全局段表,进程共享,LDT和TSS入口

LDT:局部段表,进程独有

gdtr:GDT入口地址

ldtr:当前进程的LDT索引

TSS:任务状态段,保存任务各寄存器值。通过TR寄存器访问。其保存的内容包括任务的CPU现场(通用寄存器、段选择寄存器、指令指针、标志寄存器等);特权级分别为0、1、2时的堆栈段选择符和栈顶指针;该任务被调用时,前一个任务TSS的返回连接选择符;IO允许位图等。

根据T0位是0还是1有两种不同的地址翻译过程:

T0=0:gdtr->GDT && 段选择子索引 && 偏移-> 线性地址

T0=1: gdtr->GDT && ldtr -> LDT && 段选择子索引&&偏移 ->线性地址 &&CR3 -> 页目录基地址 -> 页表 ->页框->物理地址

相关内容推荐