转载请注明: TheViper http://www.cnblogs.com/TheViper
一种存储器抽象:地址空间
把物理地址暴露给进程会带来下面几个严重问题:
1.如果用户程序可以寻址内存的每个字节,它们就可以很容易的破坏操作系统。
2.使用这种模型,想要同时(如果只有一个cpu就轮流执行)运行多个程序是很困难的。
地址空间
地址空间是一个进程可用于寻址内存的一套地址集合。每个进程都有一个自己的地址空间,并且这个地址空间独立于其他进程的地址空间(除了在一些特殊情况下进程需要共享它们的地址空间外)。
基址寄存器与界限寄存器
一个简单的解决办法是使用一种简单的动态重定向。即简单的把每个进程的地址空间映射到物理内存的不同办法。所使用的经典方法是给每个cpu配置两个特殊硬件寄存器,通常叫做基址寄存器与界限寄存器。当使用这两个寄存器时,程序会被装载到内存中的连续空间且装载期间无须重定向。
具体的,当一个程序运行时,程序的起始物理地址装载到基址寄存器,程序的长度装载到界限寄存器。
使用这种方法的缺点是,每次访问内存都需要进行加法和比较运算。比较可以做的很快,但是加法由于进位传递时间的问题,在没有使用特殊电路的情况下会很慢。
交换技术
有两种处理内存超载的通用的方法,最简单的策略是交换技术,即把一个进程完整调用内存,使该进程运行一段时间,然后把它存回磁盘。空闲进程主要存储在磁盘上,所以当它们不运行时,就不会占用内存(尽管它们的一些进程会周期性的被唤醒以完成相关工作,然后又进入睡眠状态)。
交换在内存中会产生多个空闲区,通过把所有的进程尽可能向下移动,有可能将这些小的空闲区合成一大块。该技术称为内存紧缩。这个操作通常不进行,因为要耗费大量的cpu时间。
有一个问题值得注意,即当进程被创建或换入时应该为它分配多大的内存。如果进程创建时其大小是固定的且不再改变,则按需分配。
如果进程的数据段可以增长时,若该进程与一个空闲区相邻,就把空闲区分配给该进程。若相邻的是另一个进程,那么要么把需要增长的进程移到内存中一个足够大的区域,要么把一个或多个进程交换出去,以便生成一个足够大的空闲区。若一个进程在内存中不能增长,而且磁盘的交换区也已经满了,那么这个进程只有挂起直到有空间空闲。
空闲内存管理
有两种方式跟踪内存使用情况:位图,空闲链表。
1.使用位图的存储管理
内存被划分成小到几个字或大到几千字节的分配单元。每个分配单元对应于位图中的一位,0表示空闲,1表示占用。
这种方法的主要问题是,在决定把一个占k个分配单元的进程调入内存时,存储管理器必须搜索位图,在位图中找出有k个连续0的号,查找位图中指定长度的连续0串是耗时的操作(因为在位图中该串可能跨越字的边界)。
2.使用链表
维护一个记录已分配内存段和空闲内存段的链表。链表中的每个节点包含以下域。空闲区或进程的指示标志,起始地址,长度和指向下一节点的指针。
当按照地址顺序在链表中存放进程和空闲区时,有几种算法可以为创建的进程(或从磁盘换入的已存在进程)分配内存。
这里假设存储管理器知道要为进程分配多大内存。最简单的算法是首次适配法。存储管理器沿着段链表进行搜索,直到找到一个足够大的空闲区,除非空闲区大小和要分配的空间大小一样,否则将该空闲区分为两部分,一部分供进程使用,另一部分形成新的空闲区。这是一种速度很快的算法,因为它尽可能少的搜索链表节点。
对首次适配算法进行很小的修改就可以得到下次适配算法。它的工作方式和首次适配算法一样,不同的是每次找到合适的空闲区时都记录当时的位置,以便在下次寻找空闲区时从上次结束的地方开始搜索。
最佳适配法:搜索整个链表(从开始到结束),找出能够容纳进程的最小的空闲区。最佳适配法试图找出最接近实际需要的空闲区,而不是先拆分一个以后可能会用到的大空闲区。
因为每次调用最佳适配算法时,都要扫描整个链表,所以它要比首次适配算法慢。另外,最佳适配算法比首次适配算法浪费更多的内存,因为它会产生大量无用的空闲区。
为了避免这一问题,可以考虑最差适配算法,即总是分配最大的可用空闲区,使新的空闲区比较大从而可以继续使用。
如果为进程和空闲区维护各自独立的链表,那么这四个算法都能得到提高。这样就能集中精力只检查空闲区而不是进程。
但是这样会增加复杂度,减慢内存释放速度,因为必须将一个回收的段从进程链表中删除并插入空闲区链表。
虚拟内存
基本思想:每个程序拥有自己的地址空间,这个空间被分割成多个块,每一块被称作一页。每一页有连续的地址范围。这些页被映射到物理内存,但并不是所有的页都必须在内存中才能运行程序。当程序引用到一部分在物理内存中的地址空间时,由硬件立即执行必要的映射,当程序引用到一部分不在物理内存中的地址空间时,由操作系统负责将缺失的部分装入物理内存。
分页
虚拟地址空间按照固定大小划分成页面的若干单元。
页表
作为分页的一种最简单实现。虚拟地址到物理地址的映射可以概括为如下:虚拟地址被分成虚拟页号(高位部分)和偏移量(低位部分)两部分。例如,
对于16位地址和4kb的页面大小,高4位可以指定16个虚拟页面中的一个,而低12位则确定了所选页面中的字节偏移量(0-4095)。当然,使用其他位数拆分虚拟地址也可。
不同计算机的页表项大小可能不一样,但32位是一个常用大小。最重要的域是页框号,毕竟页映射的目的是找到这个值,其次是“在/不在”位,这一位是1时,表示有效,可以使用。为0时,则表示该表项对应的虚拟页面现在不在内存中,访问该页面会引起缺页中断。
“保护”位指出一个页允许什么类型的访问,最简单的形式是这个域只有一位,0表示读/写,1表示只读。
为了记录页面的使用状况,引入了“修改”位,“访问”位.