内存管理
无存储器抽象
早期的计算机的存储器没有抽象,程序引用的内存地址都是物理地址,这样的话程序中只可以运行一个进程,如果说运行两个进程的话就容易造成一个进程访问另一个进程的地址空间,然后两个进程同时崩溃。
还可以把一个进程暂停运行后把信息保存在磁盘中,然后把另一个进程的信息从磁盘中中读取到内存中,当这个进程暂停运行后,再把另一个进程的信息从磁盘中读取到内存中,这样就会发生大量的内存交换,效率低下。
不使用存储器抽象的情况下运行多个程序
即使没有存储器抽象,也可能同时运行多个程序,操作系统只需要把当前内存中所有内容保存到磁盘文件中,然后把下一个程序读入到磁盘文件中,然后把下一个程序导数到内存中再运行即可,只要在某个时间内存中只有一个程序,那么就不会有冲突;
一种存储器抽象:地址空间
地址空间的概念
地址空间是一个进程可用于寻址内存的一套地址集合,每个进程都有一个自己的地址空间,并且这个地址空间独立于其他进程的地址空间;
基址寄存器和界限寄存器
每个CPU配置两个特殊硬件寄存器,叫做基址寄存器和界限寄存器,当使用基址寄存器和界限寄存器时,程序装载到内存中连续的空闲位置且装载期间无需重定位
使用基址寄存器和界限寄存器重定位的缺点是:每次访问内存都需要进行加法和比较运算,比较运算可以做的快,但是加法运算由于进位传递时间的问题,没有使用特殊电路的情况下会显得很慢;
交换技术
处理内存超载的通用办法之一是交换(swapping)技术,即把一个进程完整调入内存,使该进程运行一段时间,然后把它存回磁盘,空闲进程主要存储在磁盘上,所以当它们不运行时就不会占用内存,尽管它们的一些进程会周期性地被唤醒以完成相关工作,然后就又进入睡眠状态。
交换在内存中产生了多个空闲区(hole,即空洞),通过把所有的进程尽可能向下移动,有可能将这些小的空闲区合成一大块,该技术称为内存紧缩(memory compaction)。这个操作通常不进行,因为它要耗费大量的CPU时间。
考虑到进程空间会增长,在给进程分配内存空间之初,就可为此进程预留适当大小的增长空间,这样就不用通过移动相邻地址进程的的内存空间来增长自己的内存空间了。
空闲内存管理
在动态分配内存时,操作系统必须对其进行管理,有两种方法跟踪内存使用情况,位图和空闲区链表
使用位图的存储管理
使用位图方式时,内存可能被划分成小到大个字或大到几千字节的分配单位,每个分配单元对应于位图的一位,0表示空闲,1表示战用;内存分配时搜索位图、查找位图中指定长度连读串都较费时,是位图的缺点。
使用链表的存储管理
维护一个记录已分配内存段和空闲内存段的链表。其中链表中的一个结点或者包含一个进程,或者是两个进程间的一个空的空闲区。链表中的每一个结点都包含以下域:空闲区或进程的指示标志、起始地址、长度和指向下一结点的指针。若被释放的地址空间的相邻地址空间是空闲区,则需要合并这两个空闲区。
内存分配算法:
- **首次适配(first fit)**算法:
搜索链表,直到找到一个足够大的空闲区,除非空闲区大小和要分配的空间大小正好一样,否则将该空闲区分为两部分,一部分供进程使用,另一部分形成新的空闲区。 - **下次适配(next fit)**算法:
在下次寻找空闲区时从上次搜索链表结束的地方开始搜索,工作方式与首次适配法的一样。 - **最佳适配(best fit)**算法:
搜索链表,找出能够容纳进程的最小的空闲区。试图找出最接近实际需要的空闲区,以最好地区配请求和可用空闲区,而不是先拆分一个以后可能会用到的大的空闲区。 - **最差适配(worst fit)**算法:
总是分配最大的可用空闲区,使新的空闲区比较大从而可以继续使用。 - **快速适配(quick fit)**算法:
为常用大小的空闲区维护单独的链表。
**内部碎片(internal fragmentation)**是由于采用固定大小的内存分区,当一个进程不能完全使用分给它的固定内存区域时就产生了内部碎片,通常内部碎片难以完全避免。**外部碎片(external fragmentation)**是由于某些未分配的连续内存区域太小,以至于不能满足任意进程的内存分配请求,从而不能被进程利用的内存区域。
虚拟内存
虚拟内存(virtual memory)的基本思想是:每个程序拥有自己的地址空间,这个空间被分割成多个块,每一块称作一页或页面(page),每一页有连续的地址范围,这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序运行到一部分在物理内存中的地址空间时,由硬件立即执行必要的映射;当程序运行到的一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存并重新执行失败的命令。
虚拟内存是对基址寄存器和界限寄存器的一种综合。
分页
虚拟内存系统种都使用一种称为分页的技术;
由程序产生的这些地址被称为虚拟