现代操作系统学习笔记一、内存管理

本文探讨了操作系统内存管理的核心概念,包括实地址模式、Swapping技术、地址空间、基址寄存器与界址寄存器、交换与虚拟内存、分页机制、页面置换算法,以及堆栈在内存中的角色。重点介绍了如何通过虚拟内存技术实现进程隔离,以及各种页面置换算法的优缺点。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

内存管理

  从本篇文章开始总结操作系统相关的知识点,操作系统相关的内容可以分为内存管理、进程和线程、死锁三个部分。本篇文章记录内存管理部分。


  操作系统对内存管理的目的在于进程隔离。我们小时候学过“进程是操作系统资源分配的基本单位,线程是操作系统调度和执行的基本单位”,其中“进程是操作系统进行资源分配的基本单位”中所说的“资源分配”很重要的一项就是内存资源。那操作系统如何给每个进程分配内存资源?针对该问题涉及到的一系列技术称为内存管理技术。

1. 实地址模式

  Dos时期采用的是“实地址”模式,进程直接使用物理地址,这种模式下进程可以任意修改物理内存中的数据,很容易发生占用其他进程内存的情况,甚至会覆盖操作系统使用的内存。

1.1. Swapping技术

  “实地址”模式下多个进程运行在同一内存空间上,很容易发生进程间数据的覆盖,想要实现宏观上的多进程并行执行,就需要将当前运行的进程整个存入磁盘,转而去加载另一个进程到内存上,这种技术称为Swapping技术。

2. 地址空间

  要使多个应用程序同时处于内存中并且不会相互影响,需要解决两个问题:保存和重定位。一种解决方案就是为每个进程抽象出一个独立的内存地址空间,从程序角度来看,每个进程独立占用一块内存,多个进程可以拥有一样的逻辑地址。

2.1. 基址寄存器和界址寄存器

  动态重定位技术可以把每个进程的地址空间映射到物理内存的不同部分,一种经典的解决方案是给CPU配置两个硬件寄存器:基址寄存器和界址寄存器。

  每次一个进程方位内存,取一条指令,CPU会把地址发送到内存总线前,自动把基址值加到进程发错的地址上,同时检查程序提供的地址是否大于等于界址寄存器里的值。如下图中,执行JMP 28汇编指令,会执行JMP 16412进而执行CMP指令,而不是跳到28地址处执行ADD指令
在这里插入图片描述

2.2. 交换技术

  一台计算机中程序运行所需的RAM总和通常要远大于内存本身的容量。有两种解决内存超载的方案:一种策略是交换技术,另一种是虚拟内存。
  这里的交换和1.1中的交换一样,即把内存上的空闲进程完整调入磁盘,把待执行的进程调入内存。由于不同进程所需的内存不同,交换过程中会产生外部碎片,可以通过紧凑技术来解决外部碎片的问题。
在这里插入图片描述
  以上交换操作是建立在进程所占内存固定的基础之上,实际情况下进程往往会动态增长,因此在创建进程时分配内存就变得不现实,如果分配过多会产生大量内部碎片,分配过少有会造成内存溢出。
  很多编程语言都允许从堆上动态分配内存,当程序运行时内存空间会动态增加,内存区域不足会引起进程交换和移动进而产生大量开销。为了解决程序内存动态增加带来的开销问题,提出了两种解决方案:一种解决方案是,创建进程时为它分配一些额外空间;另一种解决方案是,将增长区分为数据段和栈(存储返回值,参数,局部变量等)
在这里插入图片描述

2.3. 空闲内存管理

  在动态分配内存时,操作系统必须对其进行管理,有两种跟踪内存使用情况的方法:位图和空闲链表。
在这里插入图片描述

3. 虚拟内存

  交换技术可以解决“一台计算机中程序运行所需要的RAM总和大于内存本身容量”的问题。但是它并不是一个很好的解决方案,比如一个SATA磁盘峰值几百兆,这意味着需要好几秒才能换出或者换入一个1GB的程序。

  20世纪60年代所采取的解决方案是,把程序分割成许多片段,称为覆盖(overlay,注意这是个名词)。程序开始执行时,将覆盖管理模块装入内存,该管理模块立即装入并运行覆盖0。执行完成后,覆盖0通知管理模块装入覆盖1。这种方案要求程序员必须把程序分割成多个片段,这个工作是费时且容易出错的。那是否有一种方案,可以把这些工作交给计算机来做?于是,便有了虚拟内存技术。

  虚拟内存技术是现代操作系统中普遍使用的技术。每个程序拥有自己的地址空间,这个空间被分割为很多块,称为页,每一页有连续的地址范围,这些页被映射到物理内存,当程序引用到一部分在物理内存中的地址空间时,由硬件立即执行必要的映射,当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存。

3.1. 分页机制

  分页机制是虚拟内存普遍使用的一种实现方案。由程序产生的虚拟地址构成了一个虚拟地址空间。没有虚拟内存的情况下,系统直接将虚拟地址送到内存总线上,读写操作使用具有同样地址的物理内存;有虚拟内存的情况下,虚拟地址不被直接送到内存总线上,而是送到内存管理单元(Memory Managemeng Unit,MMU),MMU把虚拟地址映射为物理内存地址。
在这里插入图片描述
  虚拟内存到物理内存的映射采用“分页机制”,MMU通过页表将逻辑地址映射为物理地址。32位系统下,每个地址占4B,物理内存中每4KB作为一页,页表以页为单位进行物理内存索引,一个页表可以索引1024个页,1024 * 4KB=4MB的内存空间,这个量级是远远不够的;再向上抽象一层,使用1024个页表进行索引,这1024个页表再由页目录进行索引,这样一个量级页表可以索引102410244KB = 4GB的内存空间。

  Windows中以链表的形式记录进程控制块(PCB),每个进程的PCB中包含一个页目录地址,页目录中存储页表地址,页表完成虚拟内存地址向物理内存地址的映射。32位系统下,这样一个两级页表足够寻址4GB内存空间。每个进程对应自己的页表,这样不同进程中,相同的线性地址会被映射到不同的物理内存地址,从而实现地址空间的隔离。

  大多数程序总是对少量的页面进行访问,执行速度通常被CPU从内存取指令和数据的速度所限制,而一个两级页表需要访问两次内存,才能完成虚拟地址向物理地址的映射。那么如何突破CPU和内存交互的速度瓶颈呢?于是,便采用了快表(Translation Lookaside Buffer, TLB)的解决方案,设置一个很小的硬件设备,将虚拟地址直接映射为物理地址,而不必再访问页表,TLB一般存放在MMU中占一页的大小。MMU进行转换时,硬件首先将虚拟页号和TLB中表现进行匹配,不命中的话,再去访问页表。

3.2. 页面置换算法

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

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

  1. 最佳置换算法 Optimal replacement algorithm (OPT)

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

  1. 最近最久未使用 Least Recently Used (LRU)

  虽然无法知道将来要使用的页面情况,但是可以知道过去使用页面的情况。LRU 将最近最久未使用的页面换出。
  为了实现 LRU,需要在内存中维护一个所有页面的链表。当一个页面被访问时,将这个页面移到链表表头。这样就能保证链表表尾的页面是最近最久未访问的。
  因为每次访问都需要更新链表,因此这种方式实现的 LRU 代价很高。

  1. 最近未使用 Not Recently Used (NRU)

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

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

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

  1. 先进先出 First In First Out (FIFO)

选择换出的页面是最先进入的页面。
该算法会将那些经常被访问的页面换出,导致缺页率升高。

  1. 第二次机会算法

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

  1. 时钟 Clock

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

3.3. 分页和分段

  连续分配方式会形成许多“碎片”,虽然可通过“紧凑”方法将许多碎片拼接成可用的大块空间,但须为之付出很大的开销,如果允许将一个进程直接分散地装入到许多不相领接的分区中,便可充分地利用内存空间。

分页存储管理方式
  在该方式中,将用户程序地址空间分为若干固定大小的区域,称为“页”或“页面”。典型的页面大小为1KB。相应的,也将内存空间分为若干个物理块或页框(frame),页和块的大小相同。这样可将用户程序的任一页放入任一物理块中,实现了离散分配。
分段存储管理方式
  这是为了满足用户要求而形成的一种储存管理方式。它把用户程序的地址空间分为若干个大小不同的段,每段可定义一组相对完整的信息。在储存器分配时,以段为单位,这些段在内存中可以不相邻接,所以也同样实现了离散分配。

两者的比较

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

段页存储管理方式
  这是分页和分段两种储存管理方式相结合的产物。程序的地址空间划分为多个拥有独立地址空间的段,每个段上的地址空间划分为大小相同的页。这样既拥有分段系统的共享保护,又拥有分页系统的虚拟内存功能。它兼具两者的优点,是目前应用较为广泛的一种储存管理方式。

3.4. 操作系统中的堆和栈

  栈: 由编译器自动释放。存放函数局部变量、返回值、参数等,操作方式类似于数据结构中的栈。栈使用的是一级缓存,通常是被调用时处于存储空间,调用完毕立即释放。
  堆: 一般由程序员分配和释放,若程序员不释放,程序结束时可能由OS回收(同时会引发内存泄漏)。分配方式类似于链表,堆则是存放在二级缓存中。
在这里插入图片描述

  缓存: 缓存存在的目的是为了解决CPU运算高速率和读取内存时低速率之间的矛盾。CPU读取数据时,先去缓存中查找,再去内存中查找。缓存分为一级缓存、二级缓存、甚至三级缓存;读取速率依次降低,容量也依次增大;一级缓存中的数据是二级缓存中部分数据的镜像,二级缓存是三级缓存中部分数据的镜像,三级缓存是内存中部分数据的镜像。

在这里插入图片描述

参考链接:https://blog.youkuaiyun.com/danzhang1010/article/details/50491512

注意:TLB和CPU缓存作用不同,TLB主要用于页表缓存;CPU Cache分为好几级,缓存内存数据副本,一般比TLB大,速度也非常快。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值