动态异长分区的存储分配与回收算法.docx
《动态异长分区的存储分配与回收算法.docx》由会员分享,可在线阅读,更多相关《动态异长分区的存储分配与回收算法.docx(54页珍藏版)》请在冰豆网上搜索。
![动态异长分区的存储分配与回收算法.docx](https://file1.bdocx.com/fileroot1/2023-1/11/ec5fed5d-2305-47f9-850d-d49a979ac0ea/ec5fed5d-2305-47f9-850d-d49a979ac0ea1.gif)
动态异长分区的存储分配与回收算法
实验5动态异长分区的存储分配与回收算法
5.1实验目的
理解存储管理的功能,掌握动态异长分区的存储分配与回收算法。
存储器是计算机系统中的关键资源,存储管理一直是操作系统的最主要功能之一。
存储管理既包括内存资源管理,也包括用于实现分级存储体系的外存资源的管理。
通常,内存与外存可采用相同或相似的管理技术,如内存采用段式存储管理,则外存也采用段式存储管理。
存储管理需要完成如下功能:
存储分配、存储共享、存储保护、存储扩充、地址映射。
当一个作业进入内存时,由操作系统将其变为进程,并为进程分配存储空间。
进程运行结束时,由操作系统将其所占用的存储空间收回。
不同的操作系统对内存空间的划分与分配方法是不同的,通常分为两类:
静态等长分区的分配和动态异长分区的分配。
静态等长分区常用于页式存储管理方式与段页式存储管理方式,存储空间被静态地划分为若干个长度相等的区域,每个区域被称作一个页面。
动态异长分区常用于界地址存储管理方式与段式存储管理方式,存储空间被动态地划分为若干个长度不等的区域。
5.2实验要求
本实验要求模拟动态异长分区的分配算法、回收算法和碎片整理算法。
5.3实验步骤
5.3.1数据结构分析
空闲区域首址
空闲区域长度
…
…
addr
size
…
…
图5-1空闲区域表
为了实现存储资源的分配和回收,操作系统需要记录内存资源使用情况,即哪些区域尚未分配,哪些区域已经分配以及分配给哪些进程等。
为此一般需要两个表,一个为分配表,另外一个为空闲区域表。
前者记录已经分配的区域,后者记录着所有当前未被进程占用的空闲区域,如图5-1所示。
显然,没有记录于表中的区域即为已被进程所占用的非空闲区域,在实际的操作系统中,这些区域登记在进程的PCB中。
而PCB中除了关于内存资源的信息外,还有其它大量信息。
由于本实验是对存储管理算法的模拟,所以用一个线程来代表一个进程,用线程驻留区域表来描述线程占用的内存空间,如图5-2所示。
线程名称
驻留区始址
驻留区大小
a
0
10
b
20
20
……
……
……
图5-2线程驻留区表
同时,需要一张表来记录各个线程对内存的请求信息,如图5-3所示。
线程名称
请求大小(KB)
预计驻留时间(秒)
thread_1
20
4
thread_2
10
5
……
……
……
图5-3内存申请表
5.3.2算法分析
常用的动态异长分区的分配算法有:
最先适应算法、最佳适应算法和最坏适应算法。
1.最先适应算法(FirstFit,FF)
对于存储申请命令,选取满足申请长度要求且起始地址最小的空闲区域。
在实现时,可将系统中所有的空闲区域按照起始地址由小到大的次序依次记录于空闲区域表中。
当进程申请存储空间时,系统由表的头部开始查找,取第一个满足要求的表目。
如果该表目所对应的区域长度恰好与所申请的区域长度相同,则将该区域全部分配给申请者。
否则将该区域分割为两部分,一部分的长度与所申请的长度相同,将其分配给申请者;另一部分的长度为原长度与分配长度之差,将其仍记录于空闲区域表中。
回收时,按回收区的首地址查询空闲区表,若有与回收区相临的空闲区,则将其合并到相临区中,否则,把回收区按照地址从低到高的顺序插入到空闲区域表的适当位置。
2.最佳适应算法(BestFit,BF)
分配时取满足申请要求且长度最小的空闲区域。
在实现时,可将系统中所有的空闲区域按照长度由小到大的次序依次记录于空闲区域表中。
与最先适应算法相类似,当进程申请存储空间时,系统由表的头部开始查找,取第一个满足要求的表目。
如果该表目所对应的区域长度恰好与所申请的区域长度相同,则将该区域全部分配给申请者。
否则将该区域分割为两部分,一部分的长度与所申请的长度相同,将其分配给申请者;另一部分即剩余部分的长度为原长度与分配长度之差,由于剩余部分的长度已经改变,所以应重新将其按长度从小到大的顺序插入到空闲区域表中。
回收时,不仅要按回收区的首地址查询空闲区表,找到与回收区相临的空闲区,将其合并到相临区中,而且要把合并后的回收区按照长度递增的顺序插入到空闲区域表的适当位置。
3.最坏适应算法(WorstFit,WF)
分配时取满足申请要求且长度最大的空闲区域。
在实现时,可将系统中所有的空闲区域按照长度由大到小的次序依次记录于空闲区域表中。
当进程申请存储空间时,取第一个表目。
如果该表目所对应的区域长度恰好与所申请的区域长度相同,则将该区域全部分配给申请者。
否则将该区域分割为两部分,一部分的长度与所申请的长度相同,将其分配给申请者;另一部分即剩余部分的长度为原长度与分配长度之差,由于剩余部分的长度已经改变,所以应重新将其按长度递减的顺序插入到空闲区域表中。
回收时,不仅要按回收区的首地址查询空闲区表,找到与回收区相临的空闲区,将其合并到相临区中,而且要把合并后的回收区按照长度递减的顺序插入到空闲区域表的适当位置。
5.3.3设计并分析测试数据
假设初始内存布局如图5-4,图中的起始地址以及大小都以KB来衡量。
起始地址
0
10
20
40
70
80
85
145
160
180
占用者
a
b
c
d
e
大小
10
10
20
30
10
5
60
15
20
20
图5-4初始内存布局
由图5-4可见,初始时共有五个线程驻留在内存,它们是a,b,c,d,e,线程驻留区表如图5-5;还有五个空闲区,空闲区域表如图5-6。
假设现在有三个线程提出内存申请,申请情况见图5-7。
经过分析我们得到在每种分配算法下这三个线程所申请到的内存情况。
图5-8是最先适应算法分配情况,图5-9是最佳适应算法分配情况,图5-10是最坏适应算法分配情况。
线程名称
驻留区始址
驻留区大小
a
0
10
b
20
20
c
70
10
d
85
60
e
160
20
thread_1
40
20
thread_2
10
10
thread_3
60
5
图5-8最先适应算法线程驻留区表
线程名称
请求大小
(KB)
预计驻留
时间(秒)
thread_1
20
4
thread_2
10
5
thread_3
5
6
图5-7内存申请表
5.3.4程序设计
程序包含两个文件,一个是头文件variable_partition.h,另一个是源程序文件variable_partition.cpp。
在头文件中定义了宏、数据结构、全局变量、函数声明,源程序中含有各个函数的实现。
在头文件中,结构体FREEAREA、REQUIRE_MEMORY、THREAD_RESIDENCE_MEMORY分别对应于图5-1、图5-2、图5-3中的一行,不同之处是为了构成链表在三个结构体中都有前向指针。
数组init_free_area_table对应于图5-6,数组init_thread_require_memory_table对应于图5-5,数组init_thread_residence_memory_table对应于图5-7,为了实现动态分配与释放,用链表重新组织空闲区域表、线程驻留区表和内存申请表,全局变量p_free_area_list是空闲区链首,p_thread_require_memory_queue是内存申请队列的队首,p_thread_residence_memory_list是线程驻留区链首,tail_thread_residence_memory_list是线程驻留区链尾,由于线程驻留区链表被内存分配函数和内存释放函数共享,故用临界区变量CS_THREAD_MEMORY_LIST来保护,同理,屏幕是所有线程共享的,所以用临界区变量CS_SCREEN来保护,空闲区链表被内存分配函数和内存释放函数共享,故用临界区变量CS_FREEAREA_LIST来保护。
h_thread是线程句柄数组,用来存放各个线程的句柄。
程序共包含25个函数,按照作用可以将它们分成五组。
第一组是主函数main(),其作用是显示主菜单并根据用户的选择执行相应功能;
第二组包括函数print_space()和函数display_thread_residence_memory(),前者用来显示若干个空格,后者用来显示线程驻留区表;
第三组共十个函数,用来实现最先适应分配法,它们的名称及功能如图5-11。
函数名称
函数功能
FF_initialize_freearea_list
初始化空闲区链表:
按地址从低到高排序
FF_delete_freearea_list
删除空闲区链表
FF_initialize_require_memory_list
初始化内存申请链表
FF_delete_require_memory_list
删除内存申请链表
FF_initialize_thread_residence_memory_list
初始化线程驻留区链表
FF_delete_thread_residence_memory_list
删除线程驻留区链表
FF_thread
线程函数:
申请内存;驻留内存;释放内存
FF_require_memory
内存申请函数
FF_release_memory
内存释放函数
FF()
初始化函数:
创建线程并等待它们结束
图5-11最先适应分配法的函数及其功能
第四组共六个函数,用来实现最佳适应分配法,它们的名称及功能如图5-12。
函数名称
函数功能
BF_initialize_freearea_list
初始化空闲区链表:
按长度递增排序
BF_thread
线程函数:
申请内存;驻留内存;释放内存
BF_require_memory
申请一段内存,成功时返回起始地址,失败时返回空
BF_release_memory
释放一段内存
BF_insert_freearea
将空闲区按大小递增的次序插入到空闲区链表中
BF()
初始化函数:
创建线程并等待它们结束
图5-12最佳适应分配法的函数及其功能
第五组共六个函数,用来实现最坏适应分配法,它们的名称及功能如图5-13。
函数名称
函数功能
WF_initialize_freearea_list
初始化空闲区链表:
按长度递减排序
WF_thread
线程函数:
申请内存;驻留内存;释放内存
WF_require_memory
申请一段内存,成功时返回起始地址,失败时返回空
WF_release_memory
释放一段内存
WF_insert_freearea
将空闲区按大小递减的次序插入到空闲区链表中
WF()
初始化函数:
创建线程并等待它们结束
图5-13最坏适应分配法的函数及其功能
5.3.5参考源代码
5.3.5.1windows下的参考源程序
下面是完整的程序清单。
头文件variable_partition.h的清单
#include
#include
#include
#include
#include
#include
#defineMAX_THREAD3
#defineBF_initialize_require_memory_listFF_initialize_require_memory_list
#defineWF_initialize_require_memory_listFF_initialize_require_memory_list
#defineBF_initialize_thread_residence_memory_listFF_initialize_thread_residence_memory_list
#defineWF_initialize_thread_residence_memory_listFF_initialize_thread_residence_memory_list
#defineWF_delete_freearea_listFF_delete_freearea_list
#defineBF_delete_freearea_listFF_delete_freearea_list
#defineWF_delete_require_memory_listFF_delete_require_memory_list
#defineBF_delete_require_memory_listFF_delete_require_memory_list
#defineWF_delete_thread_residence_memory_listFF_delete_thread_residence_memory_list
#defineBF_delete_thread_residence_memory_listFF_delete_thread_residence_memory_list
typedefstructfreearea{//表示空闲区域的数据结构
structfreearea*next;//指向下一个结点的指针
intstart_address;//空闲区起始地址
intsize;//空闲区大小
}FREEAREA;
typedefstructrequire_memory{//记录线程申请内存的数据结构
structrequire_memory*next;//指向下一个结点的指针
charthread_name[10];//线程名
intsize;//申请内存大小(以KB为单位)
intduration;//在内存的驻留时间(以秒为单位)
}REQUIRE_MEMORY;
typedefstructthread_residence_memory{//描述线程驻留区的数据结构
structthread_residence_memory*next;//指向下一个结点的指针
charthread_name[10];//线程名
intstart_address;//驻留区起始地址
intsize;//驻留区大小
}THREAD_RESIDENCE_MEMORY;
FREEAREAinit_free_area_table[5]={//测试数据:
初始空闲区表
{NULL,10,10},
{NULL,40,30},
{NULL,80,5},
{NULL,145,15},
{NULL,180,20}
};
REQUIRE_MEMORYinit_thread_require_memory_table[3]={//测试数据:
初始内存申请表
{NULL,"thread_1",20,4},
{NULL,"thread_2",10,5},
{NULL,"thread_3",5,6}
};
//测试数据:
初始线程驻留区表
THREAD_RESIDENCE_MEMORYinit_thread_residence_memory_table[5]={
{NULL,"a",0,10},
{NULL,"b",20,20},
{NULL,"c",70,10},
{NULL,"d",85,60},
{NULL,"e",160,20}
};
FREEAREA*p_free_area_list=NULL;//空闲区链首
REQUIRE_MEMORY*p_thread_require_memory_queue=NULL;//内存申请队列队首
THREAD_RESIDENCE_MEMORY*p_thread_residence_memory_list=NULL;//线程驻留区链首
THREAD_RESIDENCE_MEMORY*tail_thread_residence_memory_list=NULL;//线程驻留区链尾
CRITICAL_SECTIONCS_THREAD_MEMORY_LIST;//保护线程驻留区链表的临界区
CRITICAL_SECTIONCS_SCREEN;//保护屏幕的临界区
CRITICAL_SECTIONCS_FREEAREA_LIST;//保护空闲区链表的临界区
HANDLEh_thread[MAX_THREAD];//线程句柄数组
voidprint_space(intnum);//输出若干个空格
voiddisplay_thread_residence_memory_list();//显示线程驻留区表
//最先适应分配法的函数
FREEAREA*FF_initialize_freearea_list(FREEAREA*init_table,intnum);//初始化空闲区链表
voidFF_delete_freearea_list();//删除空闲区链表
REQUIRE_MEMORY*FF_initialize_require_memory_list(REQUIRE_MEMORY*init_table,intnum);
//初始化内存申请链表
voidFF_delete_require_memory_list();//删除内存申请链表
THREAD_RESIDENCE_MEMORY*FF_initialize_thread_residence_memory_list
(THREAD_RESIDENCE_MEMORY*init_table,intnum);//初始化线程驻留区链表
voidFF_delete_thread_residence_memory_list();//删除线程驻留区链表
voidFF_thread(void*data);//线程函数
intFF_require_memory(intsize);//内存申请函数
voidFF_release_memory(intstart_address,intsize);//内存释放函数
voidFF();//最先适应分配算法的初始化函数
//最佳适应分配算法的函数
voidBF_thread(void*data);//线程函数
intBF_require_memory(intsize);//内存申请函数
voidBF_release_memory(intstart_address,intsize);//内存释放函数
voidBF_insert_freearea(FREEAREA*free_node);//空闲区结点插入函数
voidBF();//初始化程序
voidBF_initialize_freearea_list(FREEAREA*init_table,intnum);//初始化空闲区链表
//最坏适应分配算法的函数
voidWF_thread(void*data);//线程函数
voidWF_insert_freearea(FREEAREA*free_node);//空闲区结点插入函数
voidWF_initialize_freearea_list(FREEAREA*init_table,intnum);//初始化空闲区链表
intWF_require_memory(intsize);//内存申请函数
voidWF_release_memory(intstart_address,intsize);//内存释放函数
voidWF();//初始化程序
源程序文件variable_partition.cpp的清单
#include"variable_partition.h"
intmain(intargc,char*argv[]){
charselect;
while
(1){
printf("|-----------------------------------|\n");
printf("|1:
firstfitallocation|\n");
printf("|2:
bestfitallocation|\n");
printf("|3:
worstfitallocation|\n");
printf("|4:
exit|\n");
printf("|-----------------------------------|\n");
printf("selectafunction(1~4):
");
do{
select=(char)getch();
}while(select!
='1'&&select!
='2'&&select!
='3'&&select!
='4');
system("cls");
switch(select){
case'1':
FF();
break;
case'2':
BF();
break;
case'3':
WF();
break;
case'4':
return0;
}
printf("\nPressanykeytoreturntomainmenu.");
getch();
system("cls");
}
return0;
}
voidprint_space(intnum){//显示若干个空格
inti;
for(i=0;iprintf("");
}
}
voiddisplay_thread_residence_memory_list(){//显示驻留线程链表
THREAD_RESIDENCE_MEMORY*p;
charbuffer[20];
p=p_thread_residence_memory_list;
printf("|-------------------|--------------------|------------------|\n");
printf("|thread_name|start_address(kB)|size(KB)|\n");
printf("|-------------------|--------------------|------------------|\n");
while(p!
=NULL){
printf("|%s",p->thread_name);
print_space(18-strlen(p->thread_name));
printf("|%d",p->start_address);
itoa(p->start_address,buffer,10);
print_space(19-strlen(buf