操作系统内存管理

操作系统内存管理

程序通常以二进制形式存储在磁盘上,为了执行,被调入内存放进进程空间内。在磁盘上等待调入内存的进程形成了输出队列(input queue)。
将指令和数据绑定到内存地址有以下几种情况:

  1. 编译时:如果在编译时就知道进程将在内存中的驻留地址,那么就可以生成绝对代码(absolute code)
  2. 加载时:如果在编译时并不知道进程将驻留在内存的什么地方,那么编译器就生成可重定位代码(relocatable code)。对这种情况,最后绑定会延迟到加载时才进行,如果开始地址发生变化,只需要重新加载用户代码以引入改变值
  3. 执行时:如果进程在执行时可以从一个内存段移到另一个内存段,那么绑定必须延迟到执行时才行

逻辑地址空间与物理地址空间

逻辑地址(logical address):CPU所生成的地址
物理地址(physical address):加载到内存地址寄存器的地址,或内存单元所看到的地址
运行时从虚拟地址到物理地址的映射是由内存管理单元(memory-management unit,MMU)完成的。例如:基地址寄存器被称为重定位寄存器(relocation register)。用户进程所生成的地址在提交内存前,都将加上重定位寄存器的值:基地址设定为14000,生成地址为299,那物理地址就等于14299
用户(进程)只生成逻辑地址,且认为进程的地址空间0-max。用户提供的逻辑地址,必须在使用前映射到物理地址

动态加载

一个子程序只有被调用时才会被加载进内存,所有子程序都可以以重定位的形式保留在磁盘上。当一个子程序调用另一个子程序时,调用子程序首先检查另一个子程序是否装载。如果没有,可重定位的链接程序用来加载所需要的子程序,并更新程序的地址表反映这一变化

动态链接与共享库

有些操作系统只接受静止链接,此时系统语言库的处理与其他目标模块一样,由加载程序合并到二进制程序镜像中。动态链接,将链接延迟到运行时候(类似于动态加载)。如果存在动态链接,二进制镜像中对每个库程序的饮用都有一个存根(stub)。存根是一小段代码,用来指出如何定位适当的内存驻留库程序,总而言之就是:存根它会用子程序地址来替换自己,并执行子程序。好处是,下次执行这串代码时,存根已经换成了地址,不需要再次链接产生开销。动态链接还可以用于更新库。

交换

进程可以暂时从内存中交换到备份存储上,当需要再次执行时可以调回内存中。更高级的的进程执行完后,低优先级进程可以交换回内存以继续执行。这种交换成为滚出(roll out)和滚入(roll in)
通常,一个交换出的进程需要交换回到其原有的内存空间。这一限制是由地址绑定方式决定的,如果绑定是在汇编或加载时候确定的,那进程不可以移动到不同的地址空间;如果是在运行时才确定的,由于物理地址是在运行时才进行的,那可以移动到不同的地址空间
交换需要备份存储于快速磁盘,提供对这些内存镜像的直接访问。系统有一个就绪队列,包括在备份存储或在内存中准备运行的所有进程。当CPU调度程序决定执行进程时,快速磁盘调用调度程序,检测队列里的下一个进程是否在内存里。如果不在内存里,且没有空闲内存空间,调度程序将内存中的一个进程交换出去,并换入所需要的进程,然后重新装在寄存器,将控制权交给所选择的进程

连续内存分配

内存分为两个区域,一个用于驻留操作系统,另一个用于用户进程;需要考虑如何为输入队列中需要调入内存的进程分配内存空间。采用连续内存分配(contiguous memory allocation)时,每个进程位于一个连续的内存区域
***进程保护
*是通过重定位寄存器和界限寄存器来实现的。重定位寄存器有最小的物理地址值;界限地址寄存器含有逻辑地址的范围值。逻辑地址必须小于界限寄存器

内存分配

将内存分为多个固定大小的分区(partition)。每个分区只能容纳一个进程。然而这种多分区(multiple-partition method)的方法已经已不再使用。固定分区方案的推广:在可变分区方案中,操作系统有一个表,用于记录哪些内存已用和哪些内存可用。一开始所有内存都可用于用户进程,成为一个孔(hole)。当有新进程需要内存时,为该进程查找足够大的孔。如果找到,可以从该孔为该进程分配所需内存,孔内未分配的内存可以下次再用。当进程分配到孔时,就装入内存,开始竞争CPU
在任何时候,都有一组可用孔大小列表和输入队列,操作系统会根据调度算法对输入队列进行排序。内存不断分配给进程,直到下一个进程的内存需求不能满足为止,操作系统可以等到有足够空间,或者向下扫描队列以确定是否有其他内存需求小的进程可以被满足。
通常,一组大小不同的孔分布在内存中,当分配给新进程的孔太大时,将孔分两块,剩下的换给孔集。如果心孔和其他孔相邻,那这些孔合并成大孔
分配最佳方法有:
首次适应:分配第一个遇到的足够大的孔
最佳适应:分配最小足够大的孔,必须查找整个表,产生最小剩余孔
最差适应:分配最大的孔,必须查找最大的孔

碎片
首次适应方法和最佳适应方法都会有外部碎片问题(external fragmentation)随着进程的装入和移入内存,空闲内存空间被分为小片段。当所有总的可用内存之和可以满足请求,但并不连续时,就出现了外部碎片问题。不管用什么优化,假定有N个可分配块,那么可能有0.5N个块为外部碎片。即1/3的内存可能不能使用,这一特性成为50%规则

  1. 因此可以用“块”来分配内存,但进程分配的内存可能比所要的内存要大(最后一个块可能用不完)
  2. 还可以使用紧缩(compaction)方法,移动内存内容,使得所有空闲空间合并成一块。但紧缩并非是总可能的,如果重定向是静态的,并且在汇编或装入时候进行的,就不能紧缩

分页
分页允许了非连续的无理地址空间,这样只要有空间就可以分配
分页避免了将不同大小的内存块匹配到交换空间上这样的麻烦,前面所述的内存管理方案都有这个问题,当位于内存的代码或数据需要换出时,必须现在备份存储上找空间,这就导致了备份存储也存在碎片问题,但由于访问更慢,备份存储不适合使用合并

其基本方法是将物理内存分割为较小的块,成为帧(frame),将逻辑内存也分割为同样大小的块,称为页(page)。当需要执行进程时,其页就从备份存储中调入可用的内存帧中。备份存储也分为固定大小的块,其大小与内存帧是一样的。
CPU生成的地址分为两个部分:页号(p)和页偏移(d)。页号作为页表中的索引。页表包含每页所在物理内存的基地址,这些基地址与页偏移的组合就形成了物理地址。用CPU生成的页号在页表中查找到该页的基地址,然后加上页偏移,组合后就可以送交物理单元

逻辑地址通过页表到物理内存的映射过程:页的大小通常是2的幂,如果页的大小为2^n,
?逻辑空间为2^m。那么逻辑地址的m-n表示页号

采取分页技术不会产生外部碎片,每个帧都可以分给需要他的进程。但会产生内部碎片,如果进程要求的内存并,不是页的整数倍,那最后一个帧就用不完。例如,页的大小事2048B,一个大小为72776B的进程需要35个页和1086B,该进程会得到36个帧,因此会产生接近一个帧的内部碎片。

当系统进程需要执行时,将会检查进程的大小(页数),每页都需要一帧。因此如果进程需要n页,那内存中至少有n个帧。这就是非连续的地方:进程第一页放入一个已经分配的帧,帧号放入页表。下一页分配给另一个帧,其帧号也放入页表。这个页表也同时限制了用户进程访问其他进程。有一个叫做帧表的数据结构,其中存放了哪些帧已经被调用,哪些没有。

分页环境下的保护
在分页环境下,内存保护是通过每个帧相关联的保护位来实现的,可以用一个位来定义一个页是可读写还是只读的。每次地址引用都要通过页表来查找正确的帧码。还有一个位与页表中的每一条目相关联:有效位-无效位。该位有有效时,表示相关的页在进程的逻辑地址空间内,因此是合法的。当该位是无效时,表示不在进程的逻辑地址空间内。

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值