动态异长分区内存分配与去配算法的设计-最差适应算法
一、设计目的
理解存储管理的功能,掌握动态异长分区内存管理中的最差适应算法。
二、设计要求
本设计要求模拟最差适应算法的分配算法和回收算法。
三、算法设计与分析
1、数据结构分析
为了实现存储资源的分配和回收,操作系统需要记录内存资源使用情况,即哪些区域尚未分配,哪些区域已经分配以及分配给哪些进程等。为此一般需要两个表,一个为分配表, 另外一个为空闲区域表。前者记录已经分配的区域, 后者记录着所有当前未被进程占用的空闲区域,如下图。
空闲区域首地址 | 空闲区域长度 |
---|---|
… | … |
addr | size |
… | … |
显然, 没有记录于表中的区域即为已被进程所占用的非空闲区域,在实际的操作系统中,这些区域登记在进程的PCB中。而PCB中除了关于内存资源的信息外,还有其它大量信息。
由于本设计是对存储管理算法的模拟,所以用一个线程来代表一个进程,用线程驻留区域表来描述线程占用的内存空间,如下图。
线程名称 | 驻留区起始地址 | 驻留区大小 |
---|---|---|
a | 0 | 10 |
b | 30 | 20 |
… | … | … |
同时,需要一张表来记录各个线程对内存的请求信息,如下图所示。
线程名称 | 请求大小(kb) | 预计驻留时间(秒) |
---|---|---|
thread_1 | 20 | 4 |
thread_2 | 10 | 5 |
thread_3 | 5 | 6 |
2、算法分析
分配时取满足申请要求且长度最大的空闲区域。在实现时, 可将系统中所有的空闲区域按照长度由大到小的次序依次记录于空闲区域表中。当进程申请存储空间时, 取第一个表目。如果该表目所对应的区域长度恰好与所申请的区域长度相同, 则将该区域全部分配给申请者。否则将该区域分割为两部分, 一部分的长度与所申请的长度相同, 将其分配给申请者;另一部分即剩余部分的长度为原长度与分配长度之差, 由于剩余部分的长度已经改变,所以应重新将其按长度递减的顺序插入到空闲区域表中。
回收时,不仅要按回收区的首地址查询空闲区表,找到与回收区相临的空闲区,将其合并到相临区中,而且要把合并后的回收区按照长度递减的顺序插入到空闲区域表的适当位置。
3、设计并分析测试数据
假设初始内存布局如下图,图中的起始地址以及大小都以KB来衡量。
起始地址 | 0 | 10 | 30 | 50 | 80 | 90 | 105 | 125 | 135 | 155 |
---|---|---|---|---|---|---|---|---|---|---|
占用者 | a | b | c | d | e | |||||
大小 | 10 | 20 | 20 | 30 | 10 | 15 | 20 | 10 | 20 | 5 |
由上图可见,初始时共有五个线程驻留在内存,它们是a,b,c,d,e。
线程驻留区表如下。
线程名称 | 驻留区起始地址 | 驻留区大小 |
---|---|---|
a | 0 | 10 |
b | 30 | 20 |
c | 80 | 10 |
d | 105 | 20 |
e | 135 | 20 |
还有五个空闲区,空闲区域表如下图。
空闲区首地址 | 空闲区长度 |
---|---|
10 | 20 |
50 | 30 |
90 | 15 |
125 | 10 |
155 | 5 |
经过分析我们得到在每种分配算法下这三个线程所申请到的内存情况。下图是最差适应算法分配情况。
线程名称 | 驻留区起始地址 | 驻留区大小 |
---|---|---|
a | 0 | 10 |
b | 30 | 20 |
c | 80 | 10 |
d | 105 | 20 |
e | 135 | 20 |
thread_1 | 50 | 20 |
thread_2 | 10 | 10 |
thread_3 | 90 | 5 |
四、代码
话不多说,直接上代码.
第一个是.h文件,保存的时候记得修改,并且不要和第二段代码放到一起。
#include <windows.h>
#include <conio.h>
#include <stdlib.h>
#include <stdio.h>
#include <io.h>
#include <string.h>
#define MAX_THREAD 3
typedef struct freearea{ //表示空闲区域的数据结构
struct freearea *next; //指向下一个结点的指针
int start_address; //空闲区起始地址
int size; //空闲区大小
}FREEAREA;
typedef struct require_memory{ //记录线程申请内存的数据结构
struct require_memory *next; //指向下一个结点的指针
char thread_name[10]; //线程名
int size; //申请内存大小(以KB为单位)
int duration; //在内存的驻留时间(以秒为单位)
}REQUIRE_MEMORY;
typedef struct thread_residence_memory{ //描述线程驻留区的数据结构
struct thread_residence_memory *next; //指向下一个结点的指针
char thread_name[10]; //线程名
int start_address; //驻留区起始地址
int size; //驻留区大小
}THREAD_RESIDENCE_MEMORY;
FREEAREA init_free_area_table[5]={
{NULL,10,20},
{NULL,50,30},
{NULL,90,15},
{NULL,125,10},
{NULL,155,5}
}; //测试数据:初始空闲区表
REQUIRE_MEMORY init_thread_require_memory_table[3]={
{NULL,"thread_1",20,4},
{NULL,"thread_2",10,5},
{NULL,"thread_3",5,6}
}; //测试数据:初始内存申请表
THREAD_RESIDENCE_MEMORY init_thread_residence_memory_table[5]={
{NULL,"a",0,10},
{NULL,"b",30,20},
{NULL,"c",80,10},
{NULL,"d",105,20},
{NULL,"e",135,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_SECTION CS_THREAD_MEMORY_LIST; //保护线程驻留区链表的临界区
CRITICAL_SECTION CS_SCREEN; //保护屏幕的临界区
CRITICAL_SECTION CS_FREEAREA_LIST; //保护空闲区链表的临界区
HANDLE h_thread[MAX_THREAD]; //线程句柄数组
void print_space(int num); //输出若干个空格
void display_thread_residence_memory_list(); //显示线程驻留区表
//最坏适应分配算法的函数
void WF_thread(void *data); //线程函数
void WF_delete_freearea_list(); //删除空闲区链表
REQUIRE_MEMORY *WF_initialize_require_memory_list(REQUIRE_MEMORY *init_table,int num); //初始化内存申请链表
void WF_delete_require_memory_list(); //删除内存申请链表
THREAD_RESIDENCE_MEMORY *WF_initialize_thread_residence_memory_list
(THREAD_RESIDENCE_MEMORY *init_table,int num); //初始化线程驻留区链表
void WF_delete_thread_residence_memory_list(); //删除线程驻留区链表
void WF_insert_freearea(FREEAREA *free_node); //空闲区结点插入函数
void WF_initialize_freearea_list(FREEAREA *init_table,int num); //初始化空闲区链表
int WF_require_memory(int size); //内存申请函数
void WF_release_memory(int start_address,int size); //内存释放函数
void WF(); //初始化程序
第二段.cpp文件
#include "variable_partition.h" //这里注意,第一个文件保存的什么名,引号中间就写什么
void print_space(int num){ //显示若干个空格
int i;
for(i=0;i<num;i++){
printf(" ");
}
}
void display_thread_residence_memory_list(){ //显示驻留线程链表
THREAD_RESIDENCE_MEMORY *p;
char buffer[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(buffer));
printf("| %d",p->size);
itoa(p->size, buffer, 10 );
print_space(17-strlen(buffer));
printf("|\n");
p=p->next;
};
printf("|-------------------|--------------------|------------------|\n\n");
}
//最差适应分配法:删除空闲区链表
void WF_delete_freearea_list(){
FREEAREA *temp;
temp=p_free_area_list;
while(temp!=NULL){
temp=p_free_area_list->next;
free(p_free_area_list);
p_free_area_list=temp;
}
p_free_area_list=NULL;
}
//最差适应分配法:初始化内存申请链表
REQUIRE_MEMORY *WF_initialize_require_memory_list(REQUIRE_MEMORY *init_table,int num){
REQUIRE_MEMORY *temp;
REQUIRE_MEMORY *head=NULL;
REQUIRE_MEMORY *tail=NULL;
int i;
for(i=0;i<num;i++){
temp=(REQUIRE_MEMORY *)malloc(sizeof(REQUIRE_MEMORY));
strcpy(temp->thread_name,init_table[i].thread_name);
temp->size=init_table[i].size;
temp->duration=init_table[i].duration;
temp->next=NULL;
if(head==NULL)
head=tail=temp;
else{
tail->next=temp;
tail=tail->next;
}
};
return head;
}
//最差适应分配法:删除内存申请链表
void WF_delete_require_memory_list(){
REQUIRE_MEMORY *temp;
temp=p_thread_require_memory_queue;
while(temp!=NULL){
temp=p_thread_require_memory_queue->next;
free(p_thread_require_memory_queue);
p_thread_require_memory_queue=temp;
}
p_thread_require_memory_queue=NULL;
}
//最差适应分配法:初始化线程驻留区链表
THREAD_RESIDENCE_MEMORY *WF_initialize_thread_residence_memory_list(THREAD_RESIDENCE_MEMORY *init_table,int num){
THREAD_RESIDENCE_MEMORY *temp;
THREAD_RESIDENCE_MEMORY *head=NULL;
THREAD_RESIDENCE_MEMORY *tail=NULL;
int i;
for(i=0;i<num;i++){
temp=(THREAD_RESIDENCE_MEMORY *)malloc(sizeof(THREAD_RESIDENCE_MEMORY));
strcpy(temp->thread_name,init_table[i].thread_name);
temp->start_address=init_table[i].start_address;
temp->size=init_table[i].size;
temp->next=NULL;
if(head==NULL)
head=tail=temp;
else{
tail->next=temp;
tail=tail->next;
}
};
tail_thread_residence_memory_list=tail;
return head;
}
//最差适应分配法:删除线程驻留区链表
void WF_delete_thread_residence_memory_list(){
THREAD_RESIDENCE_MEMORY *temp=p_thread_residence_memory_list;
temp=p_thread_residence_memory_list;
while(temp!=NULL){
temp=p_thread_residence_memory_list->next;
free(p_thread_residence_memory_list);
p_thread_residence_memory_list=temp;
}
p_thread_residence_memory_list=NULL;
}
//最差适应分配算法的线程:申请内存,驻留一段时间,释放内存
void WF_thread(void *data){
int start_address=-1;
THREAD_RESIDENCE_MEMORY *temp;
EnterCriticalSection(&CS_SCREEN);
printf("create thread:%s\n",((REQUIRE_MEMORY *)(data))->thread_name);
LeaveCriticalSection(&CS_SCREEN);
//申请内存
while(1){
start_address=WF_require_memory(((REQUIRE_MEMORY *)(data))->size);
if(start_address>=0)
break;
else
Sleep(1000);
}
temp=(THREAD_RESIDENCE_MEMORY *)malloc(sizeof(THREAD_RESIDENCE_MEMORY));
strcpy(temp->thread_name,((REQUIRE_MEMORY *)(data))->thread_name);
temp->start_address=start_address;
temp->size=((REQUIRE_MEMORY *)(data))->size;
temp->next=NULL;
EnterCriticalSection(&CS_THREAD_MEMORY_LIST);
//加入线程内存驻留区链表
tail_thread_residence_memory_list->next=temp;
tail_thread_residence_memory_list=tail_thread_residence_memory_list->next;
LeaveCriticalSection(&CS_THREAD_MEMORY_LIST);
//显示线程内存驻留区链表
EnterCriticalSection(&CS_SCREEN);
printf("after %s %s\n",((REQUIRE_MEMORY *)(data))->thread_name,"get memory:");
display_thread_residence_memory_list();
LeaveCriticalSection(&CS_SCREEN);
Sleep(((REQUIRE_MEMORY *)(data))->duration);
//释放内存
WF_release_memory(start_address,((REQUIRE_MEMORY *)(data))->size);
}
//最差分配算法的空闲区结点插入函数
void WF_insert_freearea(FREEAREA *free_node){
FREEAREA *p;
FREEAREA *p_next;
if(p_free_area_list==NULL)
p_free_area_list=free_node;
else{
p=p_next=p_free_area_list;
while(p_next!=NULL&&free_node->size<p_next->size){
p=p_next;
p_next=p_next->next;
}
if(p_next==NULL) //应插入到尾部
p->next=free_node;
else
if(p==p_next){ //应插入到头部
free_node->next=p;
p_free_area_list=free_node;
}
else{ //应插入到p与p_next之间
free_node->next=p_next;
p->next=free_node;
}
}
}
//最差适应分配法:初始化空闲区链表
void WF_initialize_freearea_list(FREEAREA *init_table,int num){
FREEAREA *temp;
int i;
for(i=0;i<num;i++){
temp=(FREEAREA *)malloc(sizeof(FREEAREA));
temp->start_address=init_table[i].start_address;
temp->size=init_table[i].size;
temp->next=NULL;
WF_insert_freearea(temp);
}
}
//最差适应分配算法的内存申请函数
int WF_require_memory(int size){
//请读者自己实现这段代码
int start_address;//定义需要找到的空闲区起始地址
FREEAREA* p;//定义移动指针
FREEAREA* p_next;//指向移动指针的下一个地址
FREEAREA* ptr;//记录找到的最大的空闲区
FREEAREA* ptr_f;//记录找到的最大的空闲区的上一个区域
FREEAREA* p_free_area_list_next;//定义头指针的下一个地址
EnterCriticalSection(&CS_FREEAREA_LIST); //保护空闲表临界区
p=p_free_area_list;//空闲区头指针,下一个指针均指向空闲区链表
p_next=p->next;ptr=p;ptr_f=p;
p_free_area_list_next=p_free_area_list->next;
start_address=-1;
while (p->next!=NULL) {//找到空闲分区中尺寸最大的结点
if(ptr->size<p_next->size){
ptr=p_next;
ptr_f=p;
}
p=p_next;
p_next=p_next->next;
}
if(size==ptr->size){//看找到的空闲区是否等于进程的请求
if(ptr==p_free_area_list){
start_address=p_free_area_list->start_address;
p_free_area_list=p_free_area_list_next;
free(ptr);
}
else{
start_address=ptr->start_address;
ptr_f->next=ptr->next;
free(ptr);
}
}
if(size<ptr->size){//如果空闲区大于进程的请求
start_address=ptr->start_address;
ptr->start_address+=size;
ptr->size-=size;
}
//如果小于,分配不了
LeaveCriticalSection(&CS_FREEAREA_LIST); //释放空闲表临界区
return start_address;
}
//最差适应分配算法:内存释放函数
void WF_release_memory(int start_address,int size){
//请读者自己实现这段代码
FREEAREA *p,*pp,*p_pre,*p_next,*temp=p_free_area_list;
int flag=0;//记录合并方式的标识
for(p=p_free_area_list;p!=NULL;p=p->next){//通过循环来查找哪里能合并
if(p->start_address==start_address+size){//第一种合并方法
++flag;
p_next=p;
}
else if(p->start_address+p->size==start_address){//第二种合并方法
flag+=2;
p_pre=p;
}
}
if(flag==0){//如果没有合并区域
p=(FREEAREA *)malloc(sizeof(FREEAREA));
p->start_address=start_address;
p->size=size;
WF_insert_freearea(p);
}
else if(flag==1||flag==2){
if(flag==1){//如果合并方式为第一种
p_next->start_address-=size;
p_next->size+=size;
p=p_next;
}
else{//如果合并方式为第二种
p_pre->size+=size;
p=p_pre;
}
if(p==p_free_area_list){}
else{//如果指针p不为头节点
while(temp->next!=p){
temp=temp->next;
}
if(p->size>=p_free_area_list->size){
temp->next=p->next;
p->next=p_free_area_list;
p_free_area_list=p;
}
else{
if(p->size<=temp->size){}
else{
p_pre=p_free_area_list;
while(p_pre->next->size>p->size){
p_pre=p_pre->next;
}
temp->next=p->next;
p->next=p_pre->next;
p_pre->next=p;
}
}
}
}
else{
if(p_pre==p_free_area_list){
p_pre->size+=p_next->size+size;
while(temp->next!=NULL){
if(temp->next==p_next){
temp->next=p_next->next;
}
}
free(p_next);
}
else if(p_next==p_free_area_list){
p_next->start_address=p_pre->start_address;
p_next->size+=p_pre->size+size;
while(temp->next!=NULL){
if(temp->next==p_pre){
temp->next=p_pre->next;
}
}
free(p_pre);
}
else{
while(temp->next!=NULL){
if(temp->next==p_pre){
temp->next=p_pre->next;
}
if(temp->next==p_next){
temp->next=p_next->next;
}
}
p=(FREEAREA *)malloc(sizeof(FREEAREA));
p->start_address=p_pre->start_address;
p->size=p_pre->size+p_next->size+size;
pp=p_free_area_list;
while(pp->next!=NULL){
if (pp->next==p_pre){
pp->next=p_pre->next;
}
else if(pp->next==p_next){
pp->next=p_next->next;
}
if(pp->next!=NULL){
pp=pp->next;
}
}
free(p_pre);
free(p_next);
WF_insert_freearea(p);
}
}
EnterCriticalSection(&CS_THREAD_MEMORY_LIST);//访问线程驻留区域
THREAD_RESIDENCE_MEMORY *rp=p_thread_residence_memory_list,*f;
while(rp->next->start_address!=start_address)
rp=rp->next;
f=rp->next;
rp->next=f->next;
free(f);
while (rp->next!=NULL)
rp=rp->next;
tail_thread_residence_memory_list=rp;
LeaveCriticalSection(&CS_THREAD_MEMORY_LIST);
}
//最差适应分配算法
void WF( ){
int i=0;
REQUIRE_MEMORY *p;
HANDLE h_thread[MAX_THREAD];
InitializeCriticalSection(&CS_THREAD_MEMORY_LIST);
InitializeCriticalSection(&CS_FREEAREA_LIST);
InitializeCriticalSection(&CS_SCREEN);
printf("最坏适应分配算法\n");
WF_initialize_freearea_list(init_free_area_table,5);
p_thread_require_memory_queue=WF_initialize_require_memory_list(init_thread_require_memory_table,3);
p_thread_residence_memory_list=WF_initialize_thread_residence_memory_list(init_thread_residence_memory_table,5);
p=p_thread_require_memory_queue;
while(p!=NULL){
h_thread[i]=CreateThread(NULL,0,(LPTHREAD_START_ROUTINE)(WF_thread),p,0,NULL);
i++;
p=p->next;
};
//等待所有线程结束
WaitForMultipleObjects(MAX_THREAD,h_thread,TRUE,-1);
//显示驻留线程链表
EnterCriticalSection(&CS_SCREEN);
printf("after all threads have finished:\n");
display_thread_residence_memory_list();
LeaveCriticalSection(&CS_SCREEN);
//删除各种链表
WF_delete_freearea_list();
WF_delete_require_memory_list();
WF_delete_thread_residence_memory_list();
getch();
printf("\n");
}
int main(){
WF( );
}
最后,数据都是可以自己定义修改的。其实我写的内存分配函数并没有按照要求的那样,找到之后重新排序,只是在每次都去找最大的。对于内存释放函数并不是本人写的,但是释放函数是有一个重排序的过程,想要借用的小伙伴可以注意一下。