實驗、可變分割槽儲存管理系統模擬 —— 最先適應分配演算法

小豪、精神。發表於2021-11-21

1. 實驗目的

可變分割槽分配是一種重要的儲存管理思想,目前流行的作業系統採用的分段儲存管理的基本思想就源自該方法。本實驗的目的是通過程式設計來模擬一個簡單的可變分割槽分配儲存管理系統,利用最先適應分配演算法實現。經過實驗者親自動手編寫管理程式,可以進一步加深對可變分割槽分配儲存管理方案設計思想的理解。

2. 實驗原理

固定分割槽分配按作業系統初始化時劃定的分割槽方案為作業分配記憶體,由於各分割槽的位置和大小固定,因此作業所需的記憶體大小通常小於分到的實際記憶體的大小,造成儲存空間的浪費。可變分割槽分配對此作了改進,它總是根據作業的實際需要分配剛好夠用的連續儲存空間,保證分配給作業的儲存空間都是有用的,避免了零頭的產生。

(1)   可變分割槽中的資料結構

建立描述作業的資料結構作業控制塊,至少應包括:

   作業名稱

   作業需要執行時間

   作業的記憶體需求

   作業調入主存時間

   作業執行結束時間

   作業所在分割槽的起始地址

建立描述記憶體已分配分割槽的資料結構;

建立描述記憶體未分配的空閒分割槽的資料結構;

空閒分割槽和已分配分割槽的資訊可以使用分割槽表來描述。系統中所有空閒分割槽構成分割槽表,所有已分配分割槽構成分配分割槽表。

出於效率的考慮,也可使用分割槽鏈來記錄分割槽資訊。分割槽鏈是一種雙向連結串列,連結串列的每個結點描述一個分割槽的資訊。系統中所有空閒分割槽構成空閒分割槽鏈,所有已分配分割槽構成分配分割槽鏈。分配和回收分割槽時,需要在這兩個連結串列中進行結點的查詢和插入、刪除與修改操作。為改進演算法的執行效率,可以將分割槽鏈按特定的順序排序。

分割槽鏈結點的資料結構為:

Struct Section {
          Section *pPre;  //前向指標,指向連結串列的前一個結點
          int nSart;     //分割槽的起始地址
     	    int nSize;     //分割槽的尺寸
          Section *pSuf; //後向指標,指向連結串列的後一個結點
};

  

   可變分割槽分配演算法——最先適應分配演算法

最先適應分配演算法要求空閒分割槽按地址遞增的順序排列,在進行記憶體分配時,從低地址部分向高地址部分查詢,直到找到一個能滿足要求的空閒分割槽為止。然後按作業實際大小,從該空閒區劃出一塊空間給作業,剩下的繼續留在記錄空閒分割槽的資料結構中。

(1)   可變分割槽的回收演算法

當作業執行完畢釋放記憶體時,系統首先根據回收分割槽的首地址,在分配分割槽表(鏈)中找到相應的分割槽結點,摘下該結點並插入空閒分割槽表(鏈),插入時應該根據插入點附近空閒分割槽的情況進行處理,主要有以下幾種情況:

   回收區與插入點的前一分割槽相鄰接,將這兩個分割槽合併為一個;

   回收區與插入點的後一分割槽相鄰接,將這兩個分割槽合併為一個;

   回收區與插入點的前後分割槽均相鄰接,將這三個分割槽合併為一個;

   回收區與插入點的前後分割槽均不鄰接,將這兩個分割槽合併為一個。

3. 實驗內容

(1)程式設計實現簡單的可變分割槽分配儲存管理系統。要求:

a)   建立描述作業和記憶體分割槽的資料結構。

b)   初始資訊輸入,包括記憶體初始大小、各作業資訊、使用哪種分割槽分配演算法等。這些資訊可以直接從鍵盤上輸入,也可以從檔案讀取。

c)   程式實現最先適應分配演算法,程式初始化或執行過程中都應能指定演算法。

d)   程式設計實現分割槽回收演算法,對實驗列出的幾種分割槽回收情況都應該能處理。

(2)使用本程式執行下面的一批作業,觀察記憶體的分配和回收情況。系統可用記憶體的大小為2560K。

作業號

到達時間

執行時間

要求執行時間

J1

0

15

600K

J2

1

8

1000K

J3

2

40

300K

J4

3

30

700K

J5

4

20

500K

 

4. 實驗步驟

         i.      選用合適的實驗程式開發環境。

        ii.      設計程式結構,規劃程式功能。

        iii.      完成程式的編碼與測試。

        iv.      設計實驗資料。

         v.      針對實驗資料執行程式,並將結果記錄在實驗報告上。

 5.實驗程式碼:

#include "iostream"
#include"stdlib.h" 
using namespace std;
#define Free 0 // 空閒狀態
#define Busy 1 // 已分配狀態
#define OK 1 // 分配成功
#define ERROR 0 // 分配出錯
#define MAX_length 1024 // 最大記憶體空間為 1024
int flag;
typedef struct freeSpace // 定義一個空閒區表結構
{
long size; // 分割槽大小
long address; // 分割槽首地址
int state; // 分割槽分配狀態
}ElemType;
// 線性表的雙向連結串列儲存結構
typedef struct DuLNode
{
ElemType data;
struct DuLNode *prior; // 前趨指標
struct DuLNode *next; // 後繼指標
}
DuLNode ,*DuLinkList;
DuLinkList head_Node; // 頭結點
DuLinkList end_Node; // 尾結點
int alloc(int); // 記憶體分配選擇
int free(int); // 記憶體回收
int First_fit(int); // 首次適應演算法
void show(); // 檢視分配
int Initblock(); // 初始化空間表

int Initblock() // 初始化帶頭結點的記憶體空間
{
head_Node=(DuLinkList)malloc(sizeof(DuLNode));// 動態分配頭節點內

end_Node=(DuLinkList)malloc(sizeof(DuLNode));// 動態分配尾節點記憶體

if(head_Node!=NULL)//動態記憶體申請成功 
{
head_Node->prior=NULL; // 頭結點的前驅指標指向空
head_Node->next=end_Node; // 頭結點的後繼指標指向尾

end_Node->prior=head_Node; // 尾結點的前驅指標指向頭

end_Node->next=NULL; // 尾結點的後繼指標指向空
end_Node->data.address=0; // 尾結點的地址是 0
end_Node->data.size=MAX_length; // 分割槽大小是最大分割槽
end_Node->data.state=Free; // 狀態是空
return OK;
}
else
return ERROR;
}
//主函式  
int main()
{
int ch;
Initblock(); // 設定初始空間表
int choice; // 操作標記
while(1)
{  cout<<"\n1:  分配記憶體 \t2:  回收記憶體 \t3: 記憶體使用情況顯示 \t4:  退出\n\n";
cout<<" 請選擇您的操作: ";
cin>>choice;
if(choice==1)
{
alloc(ch);
}//  分配記憶體
else if(choice==2) //  記憶體回收
{
int flag;
cout<<" 請輸入您要釋放的分割槽號: ";
cin>>flag;
free(flag);
}
else if(choice==3)
show();
else if(choice==4)
exit(0); // 退出
else // 輸入操作有誤
{
cout<<" 輸入有誤,請重試 !"<<endl;
continue;
}
}
} 

// 分配主存
int alloc(int ch)
{
int need;
cout<<"\n\n 請輸入需要分配的空間大小 :";
cin>>need;
if(need<=0)
{
cout<<"\n\n 請重新輸入分配大小 !"<<endl;
return ERROR;
}
if(First_fit(need)==OK)//呼叫首次適應演算法 
cout<<" 分配成功 !"<<endl;
else
cout<<" 記憶體不足,分配失敗 !"<<endl;
return OK;
}
// 首次適應演算法
int First_fit(int need)
{
DuLinkList temp=(DuLinkList)malloc(sizeof(DuLNode)); 

temp->data.size=need; // 設定新申請空間的大小
temp->data.state=Busy; // 設定新申請空間的狀態 

DuLNode *p=head_Node->next;
while(p)
{
if(p->data.state==Free && p->data.size==need) // 現有的空閒

{
p->data.state=Busy; // 修改該空閒塊的狀態為已分配
return OK;
break;
}
if(p->data.state==Free && p->data.size>need) // 現有的空閒

{
temp->prior=p->prior; // 修改雙向鏈

temp->next=p;
temp->data.address=p->data.address;
p->prior->next=temp;
p->prior=temp;
p->data.address+=need;//修改剩餘空閒區的首地址 
p->data.size-=need;//修改剩餘空閒區的大小 
return OK;
break;
}
p=p->next;
}
return ERROR;
}

// 回收演算法
int free(int flag)
{
DuLNode *p=head_Node;
for(int i= 0; i <= flag; i++)
if(p!=NULL)
p=p->next;
else
return ERROR;
p->data.state=Free;
if(p->prior!=head_Node && p->prior->data.state==Free)//與前面的空閒區相連 

{
p->prior->data.size+=p->data.size;
p->prior->next=p->next;
p->next->prior=p->prior;
p=p->prior;
}
if(p->next!=end_Node  && p->next->data.state==Free)// 與後面的空閒塊相連  

{
p->data.size+=p->next->data.size;
p->next->next->prior=p;
p->next=p->next->next;
}
if(p->next==end_Node && p->next->data.state==Free)// 與最後的空閒塊相連 

{
p->data.size+=p->next->data.size;
p->next=NULL;
}
return OK;
}
// 顯示主存分配情況
void show()
{
int flag = 0;
cout<<"\n\n 主存分配情況 :\n";
cout<<"++++++++++++++++++++++++++++++++++++++++++++++\n\n";
DuLNode *p=head_Node->next;
cout<<" 分割槽號 \t 起始地址 \t 分割槽大小 \t 狀態\n\n";
while(p)
{
cout<<" "<<flag++<<"\t";
cout<<" "<<p->data.address<<"\t\t";
cout<<" "<<p->data.size<<"KB\t\t";
if(p->data.state==Free)
cout<<" 空閒\n\n";
else
cout<<" 已分配 \n\n";
p=p->next;
}
cout<<"++++++++++++++++++++++++++++++++++++++++++++++\n\n";
}

  

相關文章