實驗四主存空間的分配和回收
專業:商業軟件工程 班級:商軟2班 姓名:甘佳萍 學號:201406114207
一. 目的和要求
1.1. 實驗目的
用高級語言完成一個主存空間的分配和回收程序,以加深對動態分區分配方式及其算法的理解。
1.2. 實驗要求
采用連續分配方式之動態分區分配存儲管理,使用首次適應算法、循環首次適應算法、最佳適應算法和最壞適應算法4種算法完成設計。
(1)**設計一個作業申請隊列以及作業完成后的釋放順序,實現主存的分配和回收。采用分區說明表進行。
(2)或在程序運行過程,由用戶指定申請與釋放。
(3)設計一個空閑區說明表,以保存某時刻主存空間占用情況。
把空閑區說明表的變化情況以及各作業的申請、釋放情況顯示。
二. 實驗內容
第一步:
完成程序數據結構的創建,初始化內存分配情況,創建空閑分區表和已分配分區表。
第二步:
完成為某作業分配內存空間。
- 用戶輸入作業名稱;
- 判斷作業名稱是否已經存在,如果存在則要求用戶重新輸入;
- 用戶輸入作業所占空間大小;
- 判斷是否能夠在剩余的空閑區域中找到一塊放置該作業,如果不行則要求用戶重新輸入;
- 顯示菜單,由用戶選擇使用哪一種分配算法:
1) 首次適應算法
2) 循環首次適應算法
3) 最佳適應算法
4) 最壞適應算法
6.為該作業分配內存空間,分配處理流程圖如下(size的值設定為1K)
7.屏幕顯示分配后的內存分區情況。
第三步:
完成內存空間回收;
- 由用戶輸入作業的ID,決定所要終止的作業;
- 判斷是否存在用戶所輸入的ID,如果存在則進行終止,否則提示作業不存在;
- 判斷即將終止的作業前后是否有空閑區域,如果沒有則作業所占的空間獨立成為一個空閑塊,在未分配區表中增加一項;
(思考:如何判斷前后是否有空閑塊?)
4.即將終止作業所占空間前后有空閑塊的情況:(X代表即將被終止的作業,黑色代表內存中的空閑塊)
所以,判斷某個即將被終止的作業所占空間前面是否有空閑塊的方法是:作業空間的起始地址A.begin是否等於某個空閑塊的結束地址B.end,若相等,則前面有空閑塊,則需要合並;若不相等則再判斷后面是否有空閑塊。
回答:如何判斷?
5.進行四種情況的判斷,然后分別做出相應的區塊回收操作。
回答:如何處理回收?
6.顯示回收后的內存使用情況。
根據指定的實驗課題,完成設計、編碼和調試工作,完成實驗報告。
三、 實驗方法、步驟及結果測試
1. 源程序名:壓縮包文件(rar或zip)中源程序名OS.c
可執行程序名:OS.exe
2. 原理分析及流程圖
主要總體設計問題。
(包括存儲結構,主要算法,關鍵函數的實現等)
存儲結構:
typedef struct free_table//定義一個空閑區說明表結構 { int num; //分區序號 long begin; //起始地址 long size; //分區大小 int status; //分區狀態 }ElemType; typedef struct Node// 線性表的雙向鏈表存儲結構 { ElemType data; struct Node *prior; //前趨指針 struct Node *next; //后繼指針 }Node,*LinkList; LinkList first; //頭結點 LinkList end; //尾結點 int flag;//記錄要刪除的分區序號 Status Initblock()//開創帶頭結點的內存空間鏈表 { first=(LinkList)malloc(sizeof(Node)); end=(LinkList)malloc(sizeof(Node)); first->prior=NULL; first->next=end; end->prior=first; end->next=NULL; end->data.num=1; end->data.begin=40; end->data.size=600; end->data.status=0; return SIZE; }
主要算法:
關鍵函數:
Status allocation(int a)
Status Best_fit(int request)
Status deal1(Node *p)
Status deal2(Node *p)
Status First_fit(int request)
Status Initblock()
Status recovery(int flag)
void show()
void sort()
Status Worst_fit(int request)
3. 主要程序段及其解釋:
實現主要功能的程序段,重要的是程序的注釋解釋。
源程序:
#include<stdio.h> #include<conio.h> #include<string.h> #include<stdlib.h> #define SIZE 1 #define ERROR 0 //出錯 typedef int Status; typedef struct free_table//定義一個空閑區說明表結構 { int num; //分區序號 long begin; //起始地址 long size; //分區大小 int status; //分區狀態 }ElemType; typedef struct Node// 線性表的雙向鏈表存儲結構 { ElemType data; struct Node *prior; //前趨指針 struct Node *next; //后繼指針 }Node,*LinkList; LinkList first; //頭結點 LinkList end; //尾結點 int flag;//記錄要刪除的分區序號 Status Initblock()//開創帶頭結點的內存空間鏈表 { first=(LinkList)malloc(sizeof(Node)); end=(LinkList)malloc(sizeof(Node)); first->prior=NULL; first->next=end; end->prior=first; end->next=NULL; end->data.num=1; end->data.begin=40; end->data.size=600; end->data.status=0; return SIZE; } //菜單 void menu() { printf("\n |*************內存分配和回收***********|\n"); printf(" |======================================|\n"); printf(" | 0.退出 |\n"); printf(" | 1.首次適應算法 |\n"); printf(" | 2.最佳適應算法 |\n"); printf(" | 3.最壞適應算法 |\n"); printf(" |======================================|\n"); } void sort()//分區序號重新排序 { Node *p=first->next,*q; q=p->next; for(;p!=NULL;p=p->next) { for(q=p->next;q;q=q->next) { if(p->data.num>=q->data.num) { q->data.num+=1; } } } } //顯示主存分配情況 void show() { int flag=0;//用來記錄分區序號 Node *p=first; p->data.num=0; p->data.begin=0; p->data.size=40; p->data.status=1; sort(); printf("\n\t\t》主存空間分配情況《\n"); printf("**********************************************************\n\n"); printf("分區序號\t起始地址\t分區大小\t分區狀態\n\n"); while(p) { printf("%d\t\t%d\t\t%d",p->data.num,p->data.begin,p->data.size); if(p->data.status==0) printf("\t\t空閑\n\n"); else printf("\t\t已分配\n\n"); p=p->next; } printf("**********************************************************\n\n"); } //首次適應算法 Status First_fit(int request) { //為申請作業開辟新空間且初始化 Node *p=first->next; LinkList temp=(LinkList)malloc(sizeof(Node)); temp->data.size=request; temp->data.status=1; p->data.num=1; while(p) { if((p->data.status==0)&&(p->data.size==request)) { //有大小恰好合適的空閑塊 p->data.status=1; return SIZE; break; } else if((p->data.status==0) && (p->data.size>request)) { //有空閑塊能滿足需求且有剩余 temp->prior=p->prior; temp->next=p; temp->data.begin=p->data.begin; temp->data.num=p->data.num; p->prior->next=temp; p->prior=temp; p->data.begin=temp->data.begin+temp->data.size; p->data.size-=request; p->data.num+=1; return SIZE; break; } p=p->next; } return ERROR; } //最佳適應算法 Status Best_fit(int request) { int ch; //記錄最小剩余空間 Node *p=first; Node *q=NULL; //記錄最佳插入位置 LinkList temp=(LinkList)malloc(sizeof(Node)); temp->data.size=request; temp->data.status=1; p->data.num=1; while(p) //初始化最小空間和最佳位置 { if((p->data.status==0) && (p->data.size>=request) ) { if(q==NULL) { q=p; ch=p->data.size-request; } else if(q->data.size > p->data.size) { q=p; ch=p->data.size-request; } } p=p->next; } if(q==NULL) return ERROR;//沒有找到空閑塊 else if(q->data.size==request) { q->data.status=1; return SIZE; } else { temp->prior=q->prior; temp->next=q; temp->data.begin=q->data.begin; temp->data.num=q->data.num; q->prior->next=temp; q->prior=temp; q->data.begin+=request; q->data.size=ch; q->data.num+=1; return SIZE; } return SIZE; } //最差適應算法 Status Worst_fit(int request) { int ch; //記錄最大剩余空間 Node *p=first->next; Node *q=NULL; //記錄最佳插入位置 LinkList temp=(LinkList)malloc(sizeof(Node)); temp->data.size=request; temp->data.status=1; p->data.num=1; while(p) //初始化最大空間和最佳位置 { if(p->data.status==0 && (p->data.size>=request) ) { if(q==NULL) { q=p; ch=p->data.size-request; } else if(q->data.size < p->data.size) { q=p; ch=p->data.size-request; } } p=p->next; } if(q==NULL) return ERROR;//沒有找到空閑塊 else if(q->data.size==request) { q->data.size=1; return SIZE; } else { temp->prior=q->prior; temp->next=q; temp->data.begin=q->data.begin; temp->data.num=q->data.num; q->prior->next=temp; q->prior=temp; q->data.begin+=request; q->data.size=ch; q->data.num+=1; return SIZE; } return SIZE; } //分配主存 Status allocation(int a) { int request;//申請內存大小 printf("請輸入申請分配的主存大小(單位:KB):"); scanf("%d",&request); if(request<0 ||request==0) { printf("分配大小不合適,請重試!"); return ERROR; } switch(a) { case 1: //默認首次適應算法 if(First_fit(request)==SIZE) printf("\t****分配成功!****"); else printf("\t****內存不足,分配失敗!****"); return SIZE; break; case 2: //選擇最佳適應算法 if(Best_fit(request)==SIZE) printf("\t****分配成功!****"); else printf("\t****內存不足,分配失敗!****"); return SIZE; break; case 3: //選擇最差適應算法 if(Worst_fit(request)==SIZE) printf("\t****分配成功!****"); else printf("\t****內存不足,分配失敗!****"); return SIZE; break; } } Status deal1(Node *p)//處理回收空間 { Node *q=first; for(;q!=NULL;q=q->next) { if(q==p) { if(q->prior->data.status==0&&q->next->data.status!=0) { q->prior->data.size+=q->data.size; q->prior->next=q->next; q->next->prior=q->prior; q=q->prior; q->data.status=0; q->data.num=flag-1; } if(q->prior->data.status!=0&&q->next->data.status==0) { q->data.size+=q->next->data.size; q->next=q->next->next; q->next->next->prior=q; q->data.status=0; q->data.num=flag; } if(q->prior->data.status==0&&q->next->data.status==0) { q->prior->data.size+=q->data.size; q->prior->next=q->next; q->next->prior=q->prior; q=q->prior; q->data.status=0; q->data.num=flag-1; } if(q->prior->data.status!=0&&q->next->data.status!=0) { q->data.status=0; } } } return SIZE; } Status deal2(Node *p)//處理回收空間 { Node *q=first; for(;q!=NULL;q=q->next) { if(q==p) { if(q->prior->data.status==0&&q->next->data.status!=0) { q->prior->data.size+=q->data.size; q->prior->next=q->next; q->next->prior=q->prior; q=p->prior; q->data.status=0; q->data.num=flag-1; } if(q->prior->data.status!=0&&q->next->data.status==0) { q->data.status=0; } if(q->prior->data.status==0&&q->next->data.status==0) { q->prior->data.size+=q->data.size; q->prior->next=q->next; q->next->prior=q->prior; q=q->prior; q->data.status=0; q->data.num=flag-1; } if(q->prior->data.status!=0&&q->next->data.status!=0) { q->data.status=0; } } } return SIZE; } //主存回收 Status recovery(int flag) { Node *p=first; for(;p!=NULL;p=p->next) { if(p->data.num==flag) { if(p->prior==first) { if(p->next!=end)//當前P指向的下一個不是最后一個時 { if(p->next->data.status==0) //與后面的空閑塊相連 { p->data.size+=p->next->data.size; p->next->next->prior=p; p->next=p->next->next; p->data.status=0; p->data.num=flag; } else p->data.status=0; } if(p->next==end)//當前P指向的下一個是最后一個時 { p->data.status=0; } } //結束if(p->prior==block_first)的情況 else if(p->prior!=first) { if(p->next!=end) { deal1(p); } else { deal2(p); } }//結束if(p->prior!=block_first)的情況 }//結束if(p->data.num==flag)的情況 } printf("\t****回收成功****"); return SIZE; } void main() { int i; //操作選擇標記 int a;//算法選擇標記 while(1) { menu(); printf("請選擇輸入所使用的內存分配算法 (0~3):"); scanf("%d",&a); while(a<0||a>3) { printf("\n輸入錯誤,請重新選擇輸入所使用的內存分配算法 (0~3):"); scanf("%d",&a); } switch(a) { case 1:printf("\n\t****使用首次適應算法:****\n"); break; case 2:printf("\n\t****使用最佳適應算法:****\n"); break; case 3:printf("\n\t****使用最壞適應算法:****\n"); break; case 0:printf("\n\t****退出內存分配與回收****\n"); return; } Initblock(); //開創空間表 while(1) { show(); printf("\t1: 分配內存\t2: 回收內存\t0: 退出當前內存分配算法\n"); printf("請輸入您的操作:"); scanf("%d",&i); if(i==1) allocation(a); // 分配內存 else if(i==2) // 內存回收 { printf("請輸入您要釋放的分區號:"); scanf("%d",&flag); recovery(flag); } else if(i==0) { printf("\n退出當前內存分配算法,返回主菜單\n"); break; //退出 } else //輸入操作有誤 { printf("輸入有誤,請重新輸入!"); continue; } } } }
4. 運行結果及分析
一般必須配運行結果截圖,結果是否符合預期及其分析。
(截圖需根據實際,截取有代表性的測試例子)
運行結果:
四、 實驗總結
總之,編寫主存空間的分配和回收的過程有(如解決實際問題)。從解決實際問題的角度,我們可以這樣來看:首先要了解這個問題的基本要求,即輸入、輸出、完成從輸入到輸出的要求是什么;其次,從問題的要害入手,從前到后的解決問題的每個方面,即從輸入開始入手,着重考慮如何從輸入導出輸出。在這個過程中,可確定所需的變量、數組、函數,然后確定處理的過程--算法。可得出最后的結論,進而完成程序的編寫。經過這次實驗,我對主存空間的分配和回收有了深一步的了解,同時也初步了解了內存空間的工作原理。總的來說這個實驗不是很難,還有這個實驗很有趣。