专题四 存储管理
一. 名词解释
(一)重定位技术
重定位: 逻辑地址转变为物理地址的过程
静态重定位: 在目标程序装入内存时,把程序中的指令和数据重定位
动态重定位: 在程序执行期间每次访问内存之前进行重定位
覆盖技术: 把程序按照自身逻辑结构,划分为若干功能上相对独立的程序模块,那些不会同时执行的模块共享一块内存区域
对换技术: 以程序块为单位,将暂时不能运行的程序块送入外存,从而获得内存空间
(二)分区管理技术
碎片: 在分区式内存管理系统中,在存储分配过程当中产生的,且不能供用户作业使用的主存里的小分区
固定分区法: 内存中分区的个数固定不变,各个分区的大小也固定不变且每个分区只能装入一个进程
动态分区法: 各个分区是在相应进程要进入内存时才建立的,其大小恰好适应进程大小
(三)分页与分段技术
分页技术: 将一个进程的逻辑地址空间划分成若干大小相等的部分,随后将内存划分为与页面相同大小的若干存储块
分段技术: 将程序的地址空间按内容/函数关系划分为若干个段,把内存划分与段大小相同的若干存储块
(四)虚拟存储技术
快表: 在Cache中的页表
虚拟存储技术: 扩充逻辑地址空间,一种允许进程部分装入内存就可以执行的技术
请求分页: 基于分页技术,在进程开始运行之前,将进程装入部分页面,根据进程运行的需要,依照某种算法淘汰某个页面
内存抖动: 一个进程的页面经常换入换出,花在换页的时间远大于进程执行的事件
工作集: 一个进程在某一小段时间
内访问页面的集合
二. 技术比较
(一)覆盖技术与对换技术
覆盖技术
缺点:
程序员编程时必须划分程序模块和确定模块之间的覆盖关系,即增大编程难度
对换技术
缺点:换入换出增加了CPU的开销(I/O设备)
比较:
覆盖技术 | 交换技术 |
---|---|
节约一个进程所需的空间 | 让整个进程暂存于外存 |
由程序员实现覆盖结构 | 无需程序员实现覆盖结构 |
作业/进程内关系 | 整个作业/进程之间的关系 |
(二)分区管理技术
比较:
固定分区法 | 交换技术 |
---|---|
存在内存内碎片 | 存在内存外碎片 |
三. 分页与分段技术的地址映射
分页技术
工作原理:
地址映射问题基本方法:
(1)明确页的大小,以及逻辑地址
(2)计算页号,页号 = 逻辑地址 / 页大小,偏移量 = 逻辑地址 % 页大小
(3)查页表,根据计算出来的页表得到物理块的起始地址,最后加上偏移量即为物理地址
典型例题剖析:
例:某虚拟存储器的用户编程空间共32个页面,每页为1KB,内存为16KB。假定某时刻一用户页表中已调入内存的页号和物理块号的对照表如表所示
页号 物理块号 0 5 1 10 2 4 3 7 则逻辑地址0A5C(H)所对应的物理地址为_________
解:
(1)明确页的大小: = =
(2)计算页号: = ,得到页号 = 2,偏移量 =
(3)查页表计算物理地址,页号 = 2 对应的物理块号为 4,则物理地址的起始地址为
(2)分段技术
工作原理:
地址映射的基本方法:
(1)明确段号和段内地址
(2)查阅段表,段内地址与段表所对应的段长度相比较
(3)如果段内地址大于段长,则表示地址越界,系统发出越界中断,中止程序终止运行,反之地址合法,将段内地址与该段的内存始址相加,得到所要访问单元的内存地址
典型例题剖析:
例:已知段表如表所示
段号 基址 长度 0 219 600 1 2300 14 2 90 100 3 1327 580 4 1952 96 逻辑地址的物理地址是什么?
0,430解:
(1)明确段号: 段号 = 0,段内地址 = 430
(2)查阅段表:段长 = 600
(3)比较 段长与段内地址之间的关系,段内地址 < 段长 即合法访问,即物理地址为219 + 430 = 649
四. 页面置换算法
典例剖析:
(2002 北京航空航天大学 计算机综合改编)
已知内存大小为2个页面,现在给出以下访问页面的序列 0,0,1,1,0,3,1,2,2,4,4,3,使用FIFO算法,LRU算法,OPT算法分别计算出它们的缺页数,以及缺页率
(一)FIFO算法
– 算法设计思想:
(1)这种算法总是淘汰在内存中停留时间最长的一页,即先进入内存的页,先被换出。理由:最早调入内存的页不再被使用的可能性要大于刚调入内存的页
(2)规律::缺页率随内存块增加而增加
– 模拟实验过程:
// FIFO
#include<stdio.h>
/* 内存大小为2 */
const int MAX = 2;
/* 内存初始化均为空值NULL,s数组存放访问的页面的页号 */
struct Storage
{
int num;//存放的页面的页号
int history = 0;//初始化为 0
};
/* 判断内存是否填满 */
int IsFull(Storage* s)
{
int i;
for(i = 0;i<MAX;i++)
{
if(s[i].num == -1)//未填满将确定首个空白处的位置,以便下一个缺页的页填入
return i;
}
if(i == MAX)
return -1;//表示内存已满
}
/* 判断是否需要进行页面置换 */
bool IsChange(Storage* s,int num)
{
int i ;
for(i = 0;i<MAX;i++)
{
if(s[i].num == num)//如果在内存找到相对应的页面则不需要置换
return false;
}
if(i == MAX)
return true;//在内存中未找到相对应的页面即需要进行页面置换
}
/* 找到在内存时间最长的页面*/
int LongestHistoryPosition(Storage* s)
{
int temp = -1;
int index = -1;
for(int i = 0;i<MAX;i++)
{
if(s[i].history > temp)
{
temp = s[i].history;
index = i;
}
}
return index;
}
void LRU(Storage* s,int num,int& lackpage)
{
if(IsChange(s,num))
{
int pd = IsFull(s);
if(pd == -1)//内存已满
{
int index = LongestHistoryPosition(s);
s[index].num = num;
s[index].history = 0;
}
else//内存未满
s[pd].num = num;
lackpage++;
}
for(int i = 0;i<MAX;i++)
{
if(s[i].num != -1)
s[i].history++;
}
}
int main()
{
Storage s[MAX];
/* 初始化内存 */
for(int i = 0;i<MAX;i++)
s[i].num = -1;
int vis[12] = {0,0,1,1,0,3,1,2,2,4,4,3};
int lackpage = 0;
printf("============ 置换过程 ============\n");
for(int i = 0;i<12;i++)
{
LRU(s,vis[i],lackpage);
for(int i = 0;i<MAX;i++)
{
if(s[i].num == -1)
printf("\t ");
else
printf("%d ",s[i].num);
}
printf("\n");
}
printf("==================================\n");
printf("\n");
printf("============ 统计结果 ============\n");
double result = (double)100*((double)lackpage/(double)12);
printf("缺页数: %2d \n",lackpage);
printf("缺页率: %8f %c\n",result,'%');
printf("==================================\n");
return 0;
}
– 模拟实验验证结果:
(二)OPT算法
– 算法设计思想:
为调入新页面而必须预先淘汰掉某个老页面时,所选择的老页面在将来不被使用,或者在最远的将来才被访问
– 模拟实验过程:
// OPT
#include<stdio.h>
/* 内存大小为2 */
const int MAX = 2;
/* 内存初始化均为空值NULL,s数组存放访问的页面的页号 */
struct Storage
{
int num;//存放的页面的页号
int future = 0;//初始化为 0
};
/* 判断内存是否填满 */
int IsFull(Storage* s)
{
int i;
for(i = 0;i<MAX;i++)
{
if(s[i].num == -1)//未填满将确定首个空白处的位置,以便下一个缺页的页填入
return i;
}
if(i == MAX)
return -1;//表示内存已满
}
/* 判断是否需要进行页面置换 */
bool IsChange(Storage* s,int num)
{
int i ;
for(i = 0;i<MAX;i++)
{
if(s[i].num == num)//如果在内存找到相对应的页面则不需要置换
return false;
}
if(i == MAX)
return true;//在内存中未找到相对应的页面即需要进行页面置换
}
//计算内存中将来出现的时间
void Future(Storage* s,int* vis,int position)
{
for(int i = 0;i<MAX;i++)
{
for(int j = position+1;vis[j] != s[i].num;j++)
s[i].future++;
}
}
//找出内存中将来出现的时间最大的页面
int MaxFuture(Storage* s)
{
int index = -1;
int temp = -1;
for(int i = 0;i<MAX;i++)
{
if(s[i].future > temp)
{
temp = s[i].future;
index = i;
}
}
return index;
}
void OPT(Storage* s,int num,int& lackpage,int * vis,int position)
{
if(IsChange(s,num))
{
int pd = IsFull(s);
if(pd == -1)//内存已满
{
Future(s,vis,position);
int index = MaxFuture(s);
s[index].future = 0;
s[index].num = num;
}
else//内存未满
s[pd].num = num;
lackpage++;
}
for(int i = 0;i<MAX;i++)
{
if(s[i].num != -1)
s[i].future++;
}
}
int main()
{
Storage s[MAX];
/* 初始化内存 */
for(int i = 0;i<MAX;i++)
s[i].num = -1;
int vis[12] = {0,0,1,1,0,3,1,2,2,4,4,3};
int lackpage = 0;
printf("============ 置换过程 ============\n");
for(int i = 0;i<12;i++)
{
OPT(s,vis[i],lackpage,vis,i);
for(int i = 0;i<MAX;i++)
{
if(s[i].num == -1)
printf("\t ");
else
printf("%d ",s[i].num);
}
printf("\n");
}
printf("==================================\n");
printf("\n");
printf("============ 统计结果 ============\n");
double result = (double)100*((double)lackpage/(double)12);
printf("缺页数: %2d \n",lackpage);
printf("缺页率: %8f %c\n",result,'%');
printf("==================================\n");
return 0;
}
– 模拟实验验证结果:
(三)LRU算法
– 算法设计思想:
将“最近的过去”作为“不久的将来”的近似,就可以把最近一段时间里不曾使用的页面淘汰掉,即实质上:当需要置换一页时,选择在最近一段时间里不曾使用的页面淘汰掉
– 模拟实验过程
// LRU
#include<stdio.h>
/* 内存大小为2 */
const int MAX = 2;
const int MAXN = 999;
/* 内存初始化均为空值NULL,s数组存放访问的页面的页号 */
struct Storage
{
int num;//存放的页面的页号
int history = 0;//初始化为 0
};
/* 判断内存是否填满 */
int IsFull(Storage* s)
{
int i;
for(i = 0;i<MAX;i++)
{
if(s[i].num == -1)//未填满将确定首个空白处的位置,以便下一个缺页的页填入
return i;
}
if(i == MAX)
return -1;//表示内存已满
}
/* 判断是否需要进行页面置换 */
bool IsChange(Storage* s,int num)
{
int i ;
for(i = 0;i<MAX;i++)
{
if(s[i].num == num)//如果在内存找到相对应的页面则不需要置换
return false;
}
if(i == MAX)
return true;//在内存中未找到相对应的页面即需要进行页面置换
}
/* 找到在内存时间最长的页面*/
int ShortestHistoryPosition(Storage* s)
{
int temp = MAXN;
int index = -1;
for(int i = 0;i<MAX;i++)
{
if(s[i].history < temp)
{
temp = s[i].history;
index = i;
}
}
return index;
}
void LRU(Storage* s,int num,int& lackpage)
{
if(IsChange(s,num))
{
int pd = IsFull(s);
if(pd == -1)//内存已满
{
int index = ShortestHistoryPosition(s);
s[index].num = num;
s[index].history = 0;
}
else//内存未满
s[pd].num = num;
lackpage++;
}
for(int i = 0;i<MAX;i++)
{
if(s[i].num != -1)
s[i].history++;
}
}
int main()
{
Storage s[MAX];
/* 初始化内存 */
for(int i = 0;i<MAX;i++)
s[i].num = -1;
int vis[12] = {0,0,1,1,0,3,1,2,2,4,4,3};
int lackpage = 0;
printf("============ 置换过程 ============\n");
for(int i = 0;i<12;i++)
{
LRU(s,vis[i],lackpage);
for(int i = 0;i<MAX;i++)
{
if(s[i].num == -1)
printf("\t ");
else
printf("%d ",s[i].num);
}
printf("\n");
}
printf("\n");
printf("============ 统计结果 ============\n");
double result = (double)100*((double)lackpage/(double)12);
printf("缺页数: %2d \n",lackpage);
printf("缺页率: %8f %c",result,'%');
return 0;
}
– 模拟实验验证结果:
参考文献
[1] 操作系统原理 机械工业出版社 第二版 孟庆昌 张志华
[2] 参考慕课:西安交通大学 软件学院 田丽华(副教授)