操作系统实验2—实现动态分区分配模拟程序
操作系統實驗2—實現動態分區分配模擬程序
文章目錄
- 操作系統實驗2—實現動態分區分配模擬程序
- 實驗描述
- 設計思路
- 上機代碼
- 測試結果
- 心得體會
實驗描述
實驗內容:
編寫一個可變分區存儲管理程序,模擬可變分區存儲管理方式下對內存空間的動態分配與回收。
實驗目的:
內存管理是操作系統中的核心模塊,能夠合理利用內存,在很大程度上將影響到整個計算機系統的性能。內存的分配和回收與內存管理方式有關。本實驗要求學生獨立設計并實現可變分區管理方式下的內存分配與回收模擬程序,以加深對各種分配回收算法和可變分區存儲管理方式及其實現過程的理解。
實驗要求:
1.可以隨機輸入初始可用內存空間容量,以及進程對內存空間的請求序列,支持首次適應算法、最佳適應算法和最壞適應算法,能夠在每次內存分配和回收操作后,顯示內存空間的使用情況。具體信息見測試用例格式說明。
2.空閑分區通過空閑區鏈進行管理,在內存分配時,優先考慮低地址部分的空閑區。
3.當申請空間大于可用空閑內存空間時,不滿足此次申請,仍顯示此次申請前內存空間的使用情況,后續也不再對此次申請進行任何處理。
4.進程對內存空間的申請和釋放可由用戶自定義輸入。例如,與測試用例示例輸入對應的內存空間請求序列為:
(1) 初始狀態下可用內存空間為640KB;
(2) 進程1申請130KB;
(3) 進程2申請60KB;
(4) 進程3申請100KB;
(5) 進程2釋放60KB;
(6) 進程4申請200KB;
(7) 進程3釋放100KB;
(8) 進程1釋放130KB;
(9) 進程5申請140KB;
(10) 進程6申請60KB;
(11) 進程7申請50KB;
(12) 進程6釋放60KB。
5.分別采用首次適應算法、最佳適應算法和最壞適應算法模擬內存空間的動態分配與回收,每次分配和回收后顯示出內存空間的使用情況(參見測試用例示例輸出)。
測試用例格式如下:
輸入:
動態分區分配算法選擇
可用內存空間容量
序號/進程號/申請或釋放操作/申請或釋放的容量
其中:
(1) 動態分區分配算法:
(2) 申請或釋放操作:
輸出:
序號/內存空間狀態1/內存空間狀態2…
其中,內存空間狀態表示分為兩種情況:
(1) 內存空間被占用:
內存空間起始地址-內存空間結束地址.1.占用的進程號(2) 內存空間空閑
內存空間起始地址-內存空間結束地址.0測試用例示例如下:
| 測試用例 1 | 1 640 1/1/1/130 2/2/1/60 3/3/1/100 4/2/2/60 5/4/1/200 6/3/2/100 7/1/2/130 8/5/1/140 9/6/1/60 10/7/1/50 11/6/2/60 | 1/0-129.1.1/130-639.0 2/0-129.1.1/130-189.1.2/190-639.0 3/0-129.1.1/130-189.1.2/190-289.1.3/290-639.0 4/0-129.1.1/130-189.0/190-289.1.3/290-639.0 5/0-129.1.1/130-189.0/190-289.1.3/290-489.1.4/490-639.0 6/0-129.1.1/130-289.0/290-489.1.4/490-639.0 7/0-289.0/290-489.1.4/490-639.0 8/0-139.1.5/140-289.0/290-489.1.4/490-639.0 9/0-139.1.5/140-199.1.6/200-289.0/290-489.1.4/490-639.0 10/0-139.1.5/140-199.1.6/200-249.1.7/250-289.0/290-489.1.4/490-639.0 11/0-139.1.5/140-199.0/200-249.1.7/250-289.0/290-489.1.4/490-639.0 | 1秒 | 64M | 0 |
| 測試用例 2 | 2 640 1/1/1/130 2/2/1/60 3/3/1/100 4/2/2/60 5/4/1/200 6/3/2/100 7/1/2/130 8/5/1/140 9/6/1/60 10/7/1/50 11/6/2/60 | 1/0-129.1.1/130-639.0 2/0-129.1.1/130-189.1.2/190-639.0 3/0-129.1.1/130-189.1.2/190-289.1.3/290-639.0 4/0-129.1.1/130-189.0/190-289.1.3/290-639.0 5/0-129.1.1/130-189.0/190-289.1.3/290-489.1.4/490-639.0 6/0-129.1.1/130-289.0/290-489.1.4/490-639.0 7/0-289.0/290-489.1.4/490-639.0 8/0-289.0/290-489.1.4/490-629.1.5/630-639.0 9/0-59.1.6/60-289.0/290-489.1.4/490-629.1.5/630-639.0 10/0-59.1.6/60-109.1.7/110-289.0/290-489.1.4/490-629.1.5/630-639.0 11/0-59.0/60-109.1.7/110-289.0/290-489.1.4/490-629.1.5/630-639.0 | 1秒 | 64M | 0 |
| 測試用例 3 | 3 640 1/1/1/130 2/2/1/60 3/3/1/100 4/2/2/60 5/4/1/200 6/3/2/100 7/1/2/130 8/5/1/140 9/6/1/60 10/7/1/50 11/6/2/60 | 1/0-129.1.1/130-639.0 2/0-129.1.1/130-189.1.2/190-639.0 3/0-129.1.1/130-189.1.2/190-289.1.3/290-639.0 4/0-129.1.1/130-189.0/190-289.1.3/290-639.0 5/0-129.1.1/130-189.0/190-289.1.3/290-489.1.4/490-639.0 6/0-129.1.1/130-289.0/290-489.1.4/490-639.0 7/0-289.0/290-489.1.4/490-639.0 8/0-139.1.5/140-289.0/290-489.1.4/490-639.0 9/0-139.1.5/140-199.1.6/200-289.0/290-489.1.4/490-639.0 10/0-139.1.5/140-199.1.6/200-289.0/290-489.1.4/490-539.1.7/540-639.0 11/0-139.1.5/140-289.0/290-489.1.4/490-539.1.7/540-639.0 | 1秒 | 64M | 0 |
設計思路
輸入的進程序列有序號、進程號、執行操作類型、所需內存四個屬性,毫無疑問,用結構體來存儲是再合適不過了。用鏈表來模擬內存的分配,同樣也有開始地址、結束地址等不少屬性的存儲,也是采用的結構體。
struct memory {int startaddre; //開始地址int endaddre; //結束地址int id; //標記進程號int size; //分區大小int state; //是否被占進程用標記 0 表示未被占用,1 表示被占用struct memory * next; }; typedef struct node {int no; //序號int id; //進程號int operation; //執行操作int volume; //進程所需內存內存 }PCB;程序概要設計如下圖所示:
上機代碼
代碼使用 C++ 語言進行編寫
#include<iostream> #include<cstdio> #include<cstdlib> #include<algorithm> #include<string> using namespace std; struct memory {int startaddre;//開始地址 int endaddre;//結束地址 int id;//標記進程號 int size;//分區大小 int state;//是否被占進程用標記 0 表示未被占用,1 表示被占用struct memory * next; };typedef struct node {int no;//序號 int id;//進程號 int operation;//執行操作 int volume;//進程所需內存內存 }PCB; PCB pcb[1010];//輸入進程數組 int sig=0;//算法標志 int num=0;//輸入進程大小 int total;//內存容量 PCB pc; void FF(memory *p);//首次適應 void BF(memory *p,memory *head);//最佳適應 void WF(memory *p,memory *head);//最壞適應 void FFallocate(PCB pc,memory *p) ;//最先適應分配分區算法 void BFallocate(PCB pc,memory *p,memory *head) ;//最佳適應 void WFallocate(PCB pc,memory *p,memory *head) ;//最壞適應 void free_(PCB pc,memory *p);//釋放分區算法 void input();//輸入進程序列 void output(PCB pc,memory *p) ;//輸出分區鏈表狀態函數 int main() {//程序輸入 input();memory *head,*p;head = (memory*)malloc(sizeof(memory));//初始化head->next = NULL;head->size = total;head->startaddre = 0;head->endaddre = head->size + head->startaddre - 1;head->state = 0;p = head;//選擇算法 switch (sig){case 1:FF(p);break;case 2:BF(p,head);break;case 3:WF(p,head);break;}return 0; } void input() {// freopen("osin.txt", "r", stdin); // freopen("osout.txt", "w", stdout); sig = 0;cin >> sig;//算法選擇標志total = 0;cin >> total;//輸入可用容量num = 0;//輸入進程序列while (~scanf("%d/%d/%d/%d", &pcb[num].no, &pcb[num].id, &pcb[num].operation, &pcb[num].volume)){num++;} } void output(PCB pc,memory *p)//輸出分配區狀態函數 {printf("%d",pc.no);while(p!=NULL){if(p->next!=NULL)//不是最后一個鏈表區 {if(p->state==1) //內存被占用 printf("/%d-%d.%d.%d",p->startaddre,p->endaddre,p->state,p->id);elseprintf("/%d-%d.%d",p->startaddre,p->endaddre,p->state);}else //最后一個鏈表區 ,換行 {if(p->state==1)printf("/%d-%d.%d.%d\n",p->startaddre,p->endaddre,p->state,p->id);elseprintf("/%d-%d.%d\n",p->startaddre,p->endaddre,p->state);}p=p->next;} } void FFallocate(PCB pc,memory *p) //首適應分配內存算法 { while(p!=NULL) //從鏈表首指針一直找到尾指針 {if((pc.volume<p->size)&&p->state==0)//進程未分配且能在分區分配這個進程 ,//將有剩余內存空間 ,相當于在后面插入節點 {p->id=pc.id;//分區記錄下進程號 p->state=1;//標記被占用 p->endaddre=p->startaddre+pc.volume-1;memory *add;//增加一個鏈表add=(memory *)malloc(sizeof(memory));//在p后面插入add鏈表 add->startaddre=p->endaddre+1;add->size =p->size-pc.volume;add->endaddre=add->startaddre+add->size-1;add->state=0;add->next=p->next ;//插入 p->next=add; //操作 p->size=pc.volume;break;}//進程未分配且能在分區分配這個進程 ,//沒有剩余內存空間 ,只是占用標記位改變 else if(pc.volume==p->size&&p->state==0) {p->id=pc.id;//分區記錄下進程號 p->state=1;//標記被占用break; }p=p->next;} }void BFallocate(PCB pc,memory *p,memory *head) { int sub=-1;//分區鏈表內存與將要分配進程內存之差 int minsub=-1;//分區鏈表內存與將要分配進程內存之差最小值。//初始化為-1;int flag1=0;//標記是否是第一次適應 int location=0; //記錄最小之差的鏈表位置 int len=0;//記錄鏈表位置 while(p!=NULL){if(p->state==0&&(p->size-pc.volume)>=0) //鏈表區空閑且內存比進程所需內存大則可以存進程 {//不能把sub在if外面賦值,否則sub將一直>=0 sub=p->size-pc.volume;//鏈表區與進程所需內存之差 if(flag1==0)//第一個能存進程的鏈表 {minsub=sub;//此時內存之差 location=len; //記錄鏈表位置 }else //從多個鏈表找出一個內存之差最小的{ if(sub<minsub){minsub=sub;location=len;//記錄其下標}}flag1++;}len++;//表示鏈表位置后移 p=p->next;}if(minsub>=0) /*/能存入進程minsub才>=0 /*/{ int i;p=head; //之前p指向鏈表尾指針,現在應該指向頭指針 //從頭開始尋找標志位 ,滿足則 p指向它 for(i=0;i<location;i++) {p=p->next;//p指向能放入進程且兩者內存之差最小的鏈表 }if(minsub>0){p->id=pc.id;//分區記錄下進程號 p->state=1;//標記被占用 p->endaddre=p->startaddre+pc.volume-1;//尾地址為首地址加上進程內存大小-1 memory *add;//增加一個鏈表add=(memory *)malloc(sizeof(memory));//在p后面插入add鏈表 add->startaddre=p->endaddre+1;add->size =p->size-pc.volume;add->endaddre=add->startaddre+add->size-1;add->state=0;//表示未被占用 add->next=p->next ;p->next=add;p->size=pc.volume;}else{p->id=pc.id;//分區記錄下進程號 p->state=1;//標記被占用} } } void WFallocate(PCB pc,memory *p,memory *head) { int sub=-1;//分區鏈表內存與將要分配進程內存之差 int maxsub=-1;//分區鏈表內存與將要分配進程內存之差最大值,//初始化為-1 int flag1=0;//標記是否是第一次適應 int location=0; //記錄最小之差的鏈表位置 int len=0;//記錄鏈表位置 while(p!=NULL){if(p->state==0&&(p->size-pc.volume)>=0) //鏈表區空閑且內存比進程所需內存大則可以存進程 {sub=p->size-pc.volume;//鏈表區與進程所需內存之差 if(flag1==0)//第一個能存進程的鏈表 {maxsub=sub;//此時內存之差 location=len; //記錄鏈表位置 }else //從多個鏈表找出一個內存之差最小的{ if(sub>maxsub){maxsub=sub;location=len;//記錄其下標}}flag1++;}len++;//表示鏈表位置后移 p=p->next;}if(maxsub>=0) /*/能存入進程maxsub才>=0 /*/{ int i;p=head;//之前p指向鏈表尾指針,現在應該指向頭指針 //從頭開始尋找標志位 ,滿足則 p指向它 for(i=0;i<location;i++) {p=p->next;//p指向能放入進程且兩者內存之差最小的鏈表 }if(maxsub>0){p->id=pc.id;//分區記錄下進程號 p->state=1;//標記被占用 p->endaddre=p->startaddre+pc.volume-1;//尾地址為首地址加上進程內存大小-1 memory *add;//增加一個鏈表add=(memory *)malloc(sizeof(memory));//在p后面插入add鏈表 add->startaddre=p->endaddre+1;add->size =p->size-pc.volume;add->endaddre=add->startaddre+add->size-1;add->state=0;//表示未被占用 add->next=p->next ;p->next=add;p->size=pc.volume;}else{p->id=pc.id;//分區記錄下進程號 p->state=1;//標記被占用} } }void free_(PCB pc,memory *p) {int count=0; memory *pp,*pnext;//鏈表長度大于1時,pp是p上一個鏈表 while(p!=NULL){if(p->id==pc.id) //遍歷找到將要釋放的進程位置 {if(count==0) //釋放的分配區在鏈表首部 {if(p->next!=NULL){pnext=p->next;if(pnext->state==0){p->state=0;//標記進程未被占用 //刪除q節點,p節點大小和末地址增加 p->next=pnext->next;p->size+=pnext->size;p->endaddre=pnext->endaddre;free(pnext);break;}else{p->state=0;break;}}else{p->state=0;//標記進程未被占用 break;}}else if(p->next!=NULL)//釋放的分配區在鏈表中間 {pnext=p->next;if(pp->state==1&&pnext->state==1)//前后鏈表區都有進程占用{p->state=0;//只把進程占用標記置為 0break;}//只是后面鏈表區被占用 //合并內存,刪除p指向節點 else if(pp->state==0&&pnext->state==1) {pp->next=p->next;pp->size+=p->size;pp->endaddre=p->endaddre;free(p);break;}//只是前面鏈表區被占用 //合并內存,刪除p指向節點 else if(pp->state==1&&pnext->state==0) {pp->next=p->next;pnext->size+=p->size;pnext->startaddre=p->startaddre;free(p);break;}//前后鏈表區都不被占用//合并內存,刪除p指向節點和p后面一個節點else if(pp->state==0&&pnext->state==0) {pp->next=pnext->next;pp->size+=p->size+pnext->size;pp->endaddre=pnext->endaddre;free(p);free(pnext);break;} }else if(p->next==NULL)//釋放的分配區在鏈表尾{if(pp->state==1)//前一個鏈表區不為空 {p->state=0;break;}else //前一個鏈表區為空 {pp->next=p->next;pp->state=0;pp->size+=p->size;pp->endaddre=p->startaddre;free(p);break;}} }pp=p; //pp指向下次遍歷的p指向的前一個節點 p=p->next; count++; } }void FF(memory *p)//首次適應 {int i=0;for(i=0;i<num;i++)//是否每個進程分配或釋放完 {if(pcb[i].operation==1) {FFallocate(pcb[i],p);output(pcb[i],p) ;} else //(pcb[i].operation==2){free_(pcb[i],p);output(pcb[i],p);} } } void BF(memory *p,memory *head) //最佳適應 {int i=0;for(i=0;i<num;i++)//是否每個進程分配或釋放完 {if(pcb[i].operation==1) {BFallocate(pcb[i],p,head);output(pcb[i],p) ;} else //(pcb[i].operation==2){free_(pcb[i],p);output(pcb[i],p);} } }void WF(memory *p,memory *head) //最壞適應 {int i=0;for(i=0;i<num;i++)//是否每個進程分配或釋放完 {if(pcb[i].operation==1) {WFallocate(pcb[i],p,head);output(pcb[i],p) ;} else //(pcb[i].operation==2){free_(pcb[i],p);output(pcb[i],p);} } }測試結果
程序采用黑盒測試的方式,提交到 OJ 系統上進行在線評測
可以看到,OJ 的測試用例全部通過
心得體會
通過本次實驗,上機代碼模擬實現了三種動態分區分配算法,對操作系統內部的空閑分區分配方式有了更深刻的認識和感受。FF 首次適應算法在低址部分不斷被劃分,會留下很多難以利用的、很小的空閑碎片。BF 最佳適應算法似乎是最優的,但是可能會在存儲器中留下許多難以利用的碎片。WF 最壞適應算法與最佳適應算法剛好相反,它會導致存儲器中缺乏大的空閑分區,但是未必是最壞的,它產生碎片的可能性最小。
總結
以上是生活随笔為你收集整理的操作系统实验2—实现动态分区分配模拟程序的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 操作系统实验1—实现单处理机下的进程调度
- 下一篇: 操作系统实验4—磁盘调度