作業系統儲存管理實驗課程設計報告
作業系統報告
儲存管理
姓名: 鄭兆涵
專業: 電腦科學與技術(嵌入式方向)
一、設計目的、意義
本次實驗針對:(1)儲存管理實驗,(2)主儲存器空間的分配和回收實驗,兩個實驗進行學習。
(1)儲存管理實驗:本實驗的目的是通過請求頁式儲存管理中頁面置換演算法模擬設計,瞭解虛擬儲存技術的技術特點,掌握請求頁式儲存管理的頁面置換演算法。
(2)主儲存器空間的分配和回收實驗:本實驗的目的是理解在不同的儲存管理方式下應怎樣實現主存空間的分配和回收。
二、設計分析
1.(第四章)儲存管理的主要功能之一是合理地分配空間。請求頁式管理是一種常用的虛擬儲存管理技術。以下是實驗的設計分析:
(1)通過隨機數產生一個指令序列,共320條指令。指令的地址按下述原則生成:
①50%的指令是順序執行的;
②50%的指令是均勻分佈在前地址部分;
③50%的指令是均勻分佈在後地址部分。
具體的實施方法是:
①在 [0,319] 的指令之間隨即選取一起點m;
②順序執行一條指令,即執行地址為m+1的指令;
③在前地址[0,m+1]中隨機選取一條指令並執行,該指令的地址為m′;④順序執行一條指令,其地址為 m′+ 1;
⑤在後地址[m′+ 2,319]中隨機選取一條指令並執行;
⑥重複上述步驟①-⑤,直到執行320次指令。
(2)將指令序列變換為頁地址流
設:①頁面大小為1k;
②使用者記憶體容量為4頁到32頁;
③使用者虛存容量為32k。
在使用者虛存中,按每k存放10條指令排在虛存地址,即320條指令在虛存中的存放方式為:
第0條-第9條指令為第0頁(對應虛存地址為[0,9]);
第10條-第19條指令為第一頁(對應虛存地址為[10,19]);
… …
第310條~第319條指令為第31頁(對應虛地址為[310,319])。
按以上方式,使用者指令可組成32頁。
(3)計算並輸出下述各種演算法在不同記憶體容量下的命中率。
①先進先出的演算法(FIFO);
②最近最久使用演算法(LRU);
③最佳淘汰演算法(OPT)先淘汰最不常用的頁地址;
④最少訪問頁面演算法(LFR);
⑤最近最不經常使用演算法(NUR)。
其中③和④為選擇內容。
命中率=1-頁面失效次數/頁地址流長度
在本實驗中,頁地址流長度為320,頁面失效次數為每次訪問相應指令時,該指令所對應的頁不在記憶體的次數。
(4)隨機數產生辦法,Linux或UNIX系統提供函式strand()和rand(),分別進行初始化和產生隨機數。例如:srand ();語句可初始化一個隨機數;
a[0]=10*rand()/65535*319+1;
a[1]=10*rand()/65535*a[0];
語句可用來產生a[0]與a[1]中的隨機數。
結合所學內容對實驗進行分析:
針對本實驗首先需要把握住:
(1)命中率=1-頁面失效次數/頁地址流長度;(2)在本實驗中,頁地址流長度為320,頁面失效次數為每次訪問相應指令時,該指令所對應的頁不在記憶體的次數;(3)隨機數產生辦法,Linux或UNIX系統提供函式strand()和rand(),分別進行初始化和產生隨機數,這三個提示。
需要對演算法有自己的理解:
(1)FIFO頁面置換演算法(先進先出演算法):這個演算法的基本思想是:總是先淘汰一些駐留在記憶體時間最長的頁面,即先進入記憶體的頁面先被置換掉。作業只要把進入記憶體的各個頁面按進入的時間次序用連結串列連結起來,設定一個連結串列首指標指向進入記憶體最早的一個頁面,新進入的頁面放在連結串列的尾部,需要淘汰某一個頁面時,總是淘汰替換指標所指向的頁面即可。先進先出演算法在程式按線性順序訪問邏輯地址空間時比較理想,否則效率不高。特別是在遇到迴圈執行的程式段時,往往會把頻繁訪問的頁面,因其在記憶體駐留時間過長,而週期性地淘汰掉。
(2)OPT演算法(最優演算法):這是最理想的頁面置換演算法:從記憶體中移出以後不再使用的頁面;如無這樣的頁面,則選擇以後最長時間內不需要訪問的頁面。本演算法因為頁面訪問的順序是很難預知的,所以不是一種實際的方法。
(3)LRU演算法(最近最久未使用演算法):本演算法的基本思想是:如果某一頁被訪問了,那麼它很可能馬上又被訪問;反之,如果某一頁很長時間沒有被訪問,那麼最近也不太可能會被訪問。這種演算法考慮了程式設計的區域性性原理。其實質是:當需要置換一頁時,選擇最近一段時間內最久未使用的頁面予以淘汰。
(4)LRU近似演算法:這種演算法:只要在也表內設一個“引用位”,當儲存分塊表中的某一頁被訪問時,該位由硬體自動置1,並由也表管理軟體週期性把所有引用位置0。這樣,在一個時間週期T內,某些被訪問過的頁面其引用位為1,而未被訪問過的頁面其引用位為0.通過儲存分塊表迴圈查詢引用為0的塊,在查詢過程中,那些被訪問過的頁所對應的引用位被重新置0.
(5)LFU演算法(最少訪問頁面演算法):本演算法的原理是:要求在頁面置換時置換引用計數最小的頁面,因為經常使用的頁應該有一個較大的引用次數。但是有些頁在開始時使用次數很多,但以後就不再使用,這類頁會長時間留在記憶體中,因此可以將引用計數暫存器定時右移一位,形成指數衰減的平均使用次數。此演算法的特點是:因為在每一時間間隔內,只是用暫存器的一位來記錄頁的使用情況,因此,訪問一次和訪問10000次是等效的,次演算法不能真正反映出頁面的使用情況。
(6)NUR演算法(最近最不經常使用演算法):所謂“最近未使用”,首先是要對“近”作分界線,例如CPU最近的50次程序頁面處理中,都沒有處理到的頁面。那麼可以認為有以下三種情況①如果這樣的頁面只有一個,就將其置換出,放入需要處理的新頁面;②如果有這樣的頁面多個,就在這些頁面中任取一個置換出,放入需要處理的頁面;③如果沒有這樣的頁面,就隨意置換出一個頁面。此演算法的特點是:有一個迴圈週期,每到達這個週期,所有頁面存放是否被CPUI處理的資訊的屬性均被置於初始態。
2.(第七章):在可變分割槽管理方式下采用最先適應演算法實現主存分配和實現主存回收。
提示:可變分割槽方式是按作業需要的主存空間大小來分割分割槽的。當要裝入一個作業時,根據作業需要的主存量檢視是否有足夠的空閒空間,若有,則按需要量分割一個分割槽分配給該作業;若無,則作業不能裝入。隨著作業的裝入、撤離,主存空間被分成許多個分割槽,有的分割槽被作業佔用,而有的分割槽是空閒的。例如:
為了說明哪些區是空閒的,可以用來裝入新作業,必須要有一張空閒區說明表,格式如下:
起址——指出一個空閒區的主存起始地址。
長度——指出從起始地址開始的一個連續空閒的長度。
狀態——有兩種狀態,一種是“未分配”狀態,指出對應的由起址指出的某個長度的區域是空閒區;另一種是“空表目”狀態,表示表中對應的登記專案是空白(無效),可用來登記新的空閒區(例如,作業撤離後,它所佔的區域就成了空閒區,應找一個“空表目”欄登記歸還區的起址和長度且修改狀態)。由於分割槽的個數不定,所以空閒區說明表中應有適量的狀態為“空表目”的登記欄目,否則造成表格“溢位”無法登記。
上述的這張說明表的登記情況是按提示:
(1)中的例所裝入的三個作業佔用的主存區域後填寫的。
(2)當有一個新作業要求裝入主存時,必須查空閒區說明表,從中找出一個足夠大的空閒區。有時找到的空閒區可能大於作業需要量,這時應把原來的空閒區變成兩部分:一部分分給作業佔用;另一部分又成為一個較小的空閒區。為了儘量減少由於分割造成的空閒區,而儘量儲存高地址部分有較大的連續空閒區域,以利於大型作業的裝入。為此,在空閒區說明表中,把每個空閒區按其地址順序登記,即每個後繼的空閒區其起始地址總是比前者大。為了方便查詢還可使表格“緊縮”,總是讓“空表目”欄集中在表格的後部。
(3) 採用最先適應演算法(順序分配演算法)分配主存空間。按照作業的需要量,查空閒區說明表,順序檢視登記欄,找到第一個能滿足要求的空閒區。當空閒區大於需要量時,一部分用來裝入作業,另一部分仍為空閒區登記在空閒區說明表中。由於本實驗是模擬主存的分配,所以把主存區分配給作業後並不實際啟動裝入程式裝入作業,而用輸出“分配情況”來代替。
(4) 當一個作業執行結束撤離時,作業所佔的區域應該歸還,歸還的區域如果與其它空閒區相鄰,則應合成一個較大的空閒區,登記在空閒區說明表中。例如,在提示(1)中列舉的情況下,如果作業2撤離,歸還所佔主存區域時,應與上、下相鄰的空閒區一起合成一個大的空閒區登記在空閒區說明表中。歸還主存時的回收演算法如圖4-2。
(5) 請按最先適應演算法設計主存分配和回收的程式。然後按(1)中假設主存中已裝入三個作業,且形成兩個空閒區,確定空閒區說明表的初值。現有一個需要主存量為6K的作業4申請裝入主存;然後作業3撤離;再作業2撤離。請你為它們進行主存分配和回收,把空閒區說明表的初值以及每次分配或回收後的變化顯示出來或打印出來。
3.(第七章)在分頁式管理方式下采用位示圖來表示主存分配情況,實現主存空間的分配和回收。
(1)分頁式儲存器把主存分成大小相等的若干塊,作業的資訊也按塊的大小分頁,作業裝入主存時可把作業的資訊按頁分散存放在主存的空閒塊中,為了說明主存中哪些塊已經被佔用,哪些塊是尚未分配的空閒塊,可用一張位示圖來指出。位示圖可由若干儲存單元來構成,其中每一位與一個物理塊對應,用0/1表示對應塊為空閒/已佔用。
(2)假設某系統的主存被分成大小相等的64塊,則位示圖可用8個位元組來構成,另用一單元記錄當前空閒塊數。如果已有第0,1,4,5,6,9,11,13,24,31,共10個主存塊被佔用了,那麼位示圖情況如下:
(3)當要裝入一個作業時,根據作業對主存的需要量,先查當前空閒塊數是否能滿足作業要求,若不能滿足則輸出分配不成功。若能滿足,則查位示圖,找出為“0”的一些位,置上佔用標誌“1”,從“當前空閒塊數”中減去本次佔用塊數。
按找到的計算出對應的塊號,其計算公式為:
塊號= j´8+i
其中,j表示找到的是第n個位元組,I表示對應的是第n位。
根據分配給作業的塊號,為作業建立一張頁表,頁表格式:
(4)當一個作業執行結束,歸還主存時,根據該作業的頁表可以知道應歸還的塊號,由塊號可計算出在位示圖中的對應位置,把對應位的佔用標誌清成“0”,表示對應的塊已成為空閒塊。歸還的塊數加入到當前空閒塊數中。由塊號計算在位示圖中的位置的公式如下:
位元組號 j=[塊號/8] ([ ]表示取整)
位數 i={塊號/8} ({ }表示取餘)
(5)設計實現主存分配和回收的程式。假定位示圖的初始狀態如(2)所述,現有一資訊量為5頁的作業要裝入,執行你所設計的分配程式,為作業分配主存且建立頁表(格式如(3)所述)。然後假定有另一作業執行結束,它佔用的塊號為第4,5,6和31塊,執行你所設計的回收程式,收回作業歸還的主存塊。
要求能顯示和列印分配或回收前後的位示圖和當前空閒塊數,對完成一次分配後還要顯示或列印為作業建立的頁表。
三、方案分析
1.儲存管理
2.在可變分割槽管理方式下采用最先適應演算法實現主存分配和實現主存回收。
3.在分頁式管理方式下采用位示圖來表示主存分配情況,實現主存空間的分配和回收。
四、功能模組實現
1.儲存管理
2.在可變分割槽管理方式下采用最先適應演算法實現主存分配和實現主存回收。
3.在分頁式管理方式下采用位示圖來表示主存分配情況,實現主存空間的分配和回收。
位示圖:
連結串列:
五、最終結果分析
1.儲存管理:
2.在可變分割槽管理方式下采用最先適應演算法實現主存分配和實現主存回收。
3.在分頁式管理方式下采用位示圖來表示主存分配情況,實現主存空間的分配和回收。
位示圖:
連結串列:
六、設計體會
通過切實的實驗與分析,我對於儲存系統的瞭解大大的加深了,所有的東西都再是紙上談兵,從基礎的五種演算法的實現:先進先出(FIFO)、最近最少使用(LRR)、最佳淘汰(OPT)、最少訪問(LFR)、最近最不經常使用(NUR),可以清晰看出作業系統中一些原理性的東西,他的執行,他的工作方式,不只是靠自己對著課本的文字去想想了。
而實驗七通過最優、最先、最差三種適應演算法來對主存實現分配的過程中,更是深刻的體會到其中的微妙。分頁管理中的位示圖執行結果出現之後一目瞭然,連結串列方式也是方便自如。是讓書上不動的文字活了起來。
整個實驗下來,無論是翻課本查原理,還是上百度搜程式碼,都是促進我們學習實踐的一大助力,讓課堂上一些死板的知識流轉在手指之間,躍現在熒屏上面。
七、附錄
//1.儲存管理。
#define TRUE 1
#define FALSE 0
#define INVALID -1
#define NULL 0
#define total_instruction 320 /*指令流長*/
#define total_vp 32 /*虛頁長*/
#define clear_period 50 /*清0週期*/
typedef struct /*頁面結構*/
{
int pn; //頁號 logic number
int pfn; //頁面框架號 physical frame number
int counter; //計數器
int time; //時間
}pl_type;
pl_type pl[total_vp]; /*頁面線性結構---指令序列需要使用地址*/
typedef struct pfc_struct /*頁面控制結構,排程演算法的控制結構*/
{
int pn;
int pfn;
struct pfc_struct *next;
}pfc_type;
pfc_type pfc[total_vp], *freepf_head, *busypf_head, *busypf_tail;
int diseffect, a[total_instruction]; /* a[]為指令序列*/
int page[total_instruction], offset[total_instruction];/*地址資訊*/
int initialize(int);
int FIFO(int);
int LRU(int);
int LFU(int);
int NUR(int); //not use recently
int OPT(int);
int main( )
{
int s,i,j;
srand(10*getpid()); /*由於每次執行時程序號不同,故可用來作為初始化隨機數佇列的“種子”*/
s=(float)319*rand( )/32767/32767/2+1; /*正態分佈*/
for(i=0;i<total_instruction;i+=4) /*產生指令佇列*/
{
if(s<0||s>319)
{
printf("When i==%d,Error,s==%d\n",i,s);
exit(0);
}
a[i]=s; /*任選一指令訪問點m*/
a[i+1]=a[i]+1; /*順序執行一條指令*/
a[i+2]=(float)a[i]*rand( )/32767/32767/2; /*執行前地址指令m*/
a[i+3]=a[i+2]+1; /*順序執行一條指令*/
s=(float)(318-a[i+2])*rand( )/32767/32767/2+a[i+2]+2;
if((a[i+2]>318)||(s>319))
printf("a[%d+2],a number which is :%d and s==%d\n",i,a[i+2],s);
}
for (i=0;i<total_instruction;i++) /*將指令序列變換成頁地址流*/
{
page[i]=a[i]/10;
offset[i]=a[i]%10;
}
for(i=4;i<=32;i++) /*使用者記憶體工作區從4個頁面到32個頁面*/
{
printf("---%2d page frames---\n",i);
FIFO(i);
LRU(i);
LFU(i);
NUR(i);
OPT(i);
}
return 0;
}
/*初始化相關資料結構 total_pf表示記憶體的塊數 */
int initialize(int total_pf)
{
int i;
diseffect=0;
for(i=0;i<total_vp;i++)
{
pl[i].pfn=INVALID; /*置頁面控制結構中的頁號,頁面為空*/
pl[i].counter=0; /*頁面控制結構中的訪問次數為0*/
pl[i].time=-1; /*訪問的時間*/
}
for(i=0;i<total_pf-1;i++) /*建立pfc[i-1]和pfc[i]之間的連結*/
{
pfc[i].next=&pfc[i+1];
pfc[i].pfn=i;
}
pfc[total_pf-1].next=NULL;
pfc[total_pf-1].pfn=total_pf-1;
freepf_head=&pfc[0]; /*空頁面佇列的頭指標為pfc[0]*/
return 0;
}
int FIFO(int total_pf) /*先進先出演算法total_pf:使用者程序的記憶體頁面數*/
{
int i,j;
pfc_type *p; /*中間變數*/
initialize(total_pf); /*初始化相關頁面控制用資料結構*/
busypf_head=busypf_tail=NULL; /*忙頁面佇列頭,佇列尾連結*/
for(i=0;i<total_instruction;i++)
{
if(pl[page[i]].pfn==INVALID) /*頁面失效*/
{
diseffect+=1; /*失效次數*/
if(freepf_head==NULL) /*無空閒頁面*/
{
p=busypf_head->next;
pl[busypf_head->pn].pfn=INVALID;
freepf_head=busypf_head; /*釋放忙頁面佇列的第一個頁面*/
freepf_head->next=NULL; /*表明還是缺頁*/
busypf_head=p;
}
p=freepf_head->next;
freepf_head->pn=page[i];
pl[page[i]].pfn=freepf_head->pfn;
freepf_head->next=NULL; /*使busy的尾為null*/
if(busypf_tail==NULL)
{
busypf_tail=busypf_head=freepf_head;
}
else
{
busypf_tail->next=freepf_head;
busypf_tail=freepf_head;
}
freepf_head=p;
}
}
printf("FIFO:%6.4f ",1-(float)diseffect/320);
return 0;
}
int LRU (int total_pf) /*最近最久未使用演算法least recently used*/
{
int min,minj,i,j,present_time; /*minj為最小值下標*/
initialize(total_pf);
present_time=0;
for(i=0;i<total_instruction;i++)
{
if(pl[page[i]].pfn==INVALID) /*頁面失效*/
{
diseffect++;
if(freepf_head==NULL) /*無空閒頁面*/
{
min=32767; /*設定最大值*/
for(j=0;j<total_vp;j++) /*找出time的最小值*/
{
if(min>pl[j].time&&pl[j].pfn!=INVALID)
{
min=pl[j].time;
minj=j;
}
}
freepf_head=&pfc[pl[minj].pfn]; //騰出一個單元
pl[minj].pfn=INVALID;
pl[minj].time=0;
freepf_head->next=NULL;
}
pl[page[i]].pfn=freepf_head->pfn; //有空閒頁面,改為有效
pl[page[i]].time=present_time;
freepf_head=freepf_head->next; //減少一個free 頁面
}
else
{
pl[page[i]].time=present_time; //命中則增加該單元的訪問次數
present_time++;
}
}
printf("LRU:%6.4f ",1-(float)diseffect/320);
return 0;
}
int NUR(int total_pf ) /*最近未使用演算法Not Used recently count表示*/
{
int i,j,dp,cont_flag,old_dp;
pfc_type *t;
initialize(total_pf);
dp=0;
for(i=0;i<total_instruction;i++)
{
if (pl[page[i]].pfn==INVALID) /*頁面失效*/
{
diseffect++;
if(freepf_head==NULL) /*無空閒頁面*/
{
cont_flag=TRUE;
old_dp=dp;
while(cont_flag)
{
if(pl[dp].counter==0&&pl[dp].pfn!=INVALID)
cont_flag=FALSE;
else
{
dp++;
if(dp==total_vp)
dp=0;
if(dp==old_dp)
for(j=0;j<total_vp;j++)
pl[j].counter=0;
}
}
freepf_head=&pfc[pl[dp].pfn];
pl[dp].pfn=INVALID;
freepf_head->next=NULL;
}
pl[page[i]].pfn=freepf_head->pfn;
freepf_head->pn=page[i];
freepf_head=freepf_head->next;
}
else
pl[page[i]].counter=1;
if(i%clear_period==0)
for(j=0;j<total_vp;j++)
pl[j].counter=0;
}
printf("NUR:%6.4f ",1-(float)diseffect/320);
return 0;
}
int OPT(int total_pf) /*最佳置換演算法*/
{
int i,j, max,maxpage,d,dist[total_vp];
pfc_type *t;
initialize(total_pf);
for(i=0;i<total_instruction;i++)
{
if(pl[page[i]].pfn==INVALID) /*頁面失效*/
{
diseffect++;
if(freepf_head==NULL) /*無空閒頁面*/
{
for(j=0;j<total_vp;j++)
{
if(pl[j].pfn!=INVALID)
dist[j]=32767;
else
dist[j]=0;
}
for(j=0;j<total_vp;j++)
{
if((pl[j].pfn!=INVALID)&&(dist[j]==32767))
{
dist[j]=j;
}
}
max=0;
for(j=0;j<total_vp;j++)
if(max<dist[j])
{
max=dist[j];
maxpage=j;
}
freepf_head=&pfc[pl[maxpage].pfn];
freepf_head->next=NULL;
pl[maxpage].pfn=INVALID;
}
pl[page[i]].pfn=freepf_head->pfn;
freepf_head=freepf_head->next;
}
}
printf("OPT:%6.4f\n",1-(float)diseffect/320);
return 0;
}
/*該演算法時根據已知的預測未知的,least frequency Used是最不經常使用置換法*/
int LFU(int total_pf)
{
int i,j,min,minpage;
pfc_type *t;
initialize(total_pf);
for(i=0;i<total_instruction;i++)
{
if(pl[page[i]].pfn==INVALID) /*頁面失效*/
{
diseffect++;
if(freepf_head==NULL) /*無空閒頁面*/
{
min=32767;
/*獲取counter的使用用頻率最小的記憶體*/
for(j=0;j<total_vp;j++)
{
if(min>pl[j].counter&&pl[j].pfn!=INVALID)
{
min=pl[j].counter;
minpage=j;
}
}
freepf_head=&pfc[pl[minpage].pfn];
pl[minpage].pfn=INVALID;
pl[minpage].counter=0;
freepf_head->next=NULL;
}
pl[page[i]].pfn=freepf_head->pfn; //有空閒頁面,改為有效
pl[page[i]].counter++;
freepf_head=freepf_head->next; //減少一個free 頁面
}
else
{
pl[page[i]].counter;
pl[page[i]].counter=pl[page[i]].counter+1;
}
}
printf("LFU:%6.4f ",1-(float)diseffect/320);
return 0;
}
//2.在可變分割槽管理方式下采用最先適應演算法實現主存分配和實現主存回收。
#include<iostream>
#include<stdlib.h>
using namespace std;
#define Free 0 //空閒狀態
#define Busy 1 //已用狀態
#define OK 1 //完成
#define ERROR 0 //出錯
#define MAX_length 640 //最大記憶體空間為640KB
typedef int Status;
int flag;
typedef struct freearea//定義一個空閒區說明表結構
{
long size; //分割槽大小
long address; //分割槽地址
int state; //狀態
}ElemType;
// 線性表的雙向連結串列儲存結構
typedef struct DuLNode
{
ElemType data;
struct DuLNode *prior; //前趨指標
struct DuLNode *next; //後繼指標
}
DuLNode,*DuLinkList;
DuLinkList block_first; //頭結點
DuLinkList block_last; //尾結點
Status alloc(int);//記憶體分配
Status free(int); //記憶體回收
Status First_fit(int);//首次適應演算法
Status Best_fit(int); //最佳適應演算法
Status Worst_fit(int); //最差適應演算法
void show();//檢視分配
Status Initblock();//開創空間表
Status Initblock()//開創帶頭結點的記憶體空間連結串列
{
block_first=(DuLinkList)malloc(sizeof(DuLNode));
block_last=(DuLinkList)malloc(sizeof(DuLNode));
block_first->prior=NULL;
block_first->next=block_last;
block_last->prior=block_first;
block_last->next=NULL;
block_last->data.address=0;
block_last->data.size=MAX_length;
block_last->data.state=Free;
return OK;
}
//分配主存
Status alloc(int ch)
{
int request = 0;
cout<<"請輸入需要分配的主存大小(單位:KB):";
cin>>request;
if(request<0 ||request==0)
{
cout<<"分配大小不合適,請重試!"<<endl;
return ERROR;
}
if(ch==2) //選擇最佳適應演算法
{
if(Best_fit(request)==OK) cout<<"分配成功!"<<endl;
else cout<<"記憶體不足,分配失敗!"<<endl;
return OK;
}
if(ch==3) //選擇最差適應演算法
{
if(Worst_fit(request)==OK) cout<<"分配成功!"<<endl;
else cout<<"記憶體不足,分配失敗!"<<endl;
return OK;
}
else //預設首次適應演算法
{
if(First_fit(request)==OK) cout<<"分配成功!"<<endl;
else cout<<"記憶體不足,分配失敗!"<<endl;
return OK;
}
}
//首次適應演算法
Status First_fit(int request)
{
//為申請作業開闢新空間且初始化
DuLinkList temp=(DuLinkList)malloc(sizeof(DuLNode));
temp->data.size=request;
temp->data.state=Busy;
DuLNode *p=block_first->next;
while(p)
{
if(p->data.state==Free && p->data.size==request)
{//有大小恰好合適的空閒塊
p->data.state=Busy;
return OK;
break;
}
if(p->data.state==Free && p->data.size>request)
{//有空閒塊能滿足需求且有剩餘
temp->prior=p->prior;
temp->next=p;
temp->data.address=p->data.address;
p->prior->next=temp;
p->prior=temp;
p->data.address=temp->data.address+temp->data.size;
p->data.size-=request;
return OK;
break;
}
p=p->next;
}
return ERROR;
}
//最佳適應演算法
Status Best_fit(int request)
{
int ch; //記錄最小剩餘空間
DuLinkList temp=(DuLinkList)malloc(sizeof(DuLNode));
temp->data.size=request;
temp->data.state=Busy;
DuLNode *p=block_first->next;
DuLNode *q=NULL; //記錄最佳插入位置
while(p) //初始化最小空間和最佳位置
{
if(p->data.state==Free && (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.state=Busy;
return OK;
}
else
{
temp->prior=q->prior;
temp->next=q;
temp->data.address=q->data.address;
q->prior->next=temp;
q->prior=temp;
q->data.address+=request;
q->data.size=ch;
return OK;
}
return OK;
}
//最差適應演算法
Status Worst_fit(int request)
{
int ch; //記錄最大剩餘空間
DuLinkList temp=(DuLinkList)malloc(sizeof(DuLNode));
temp->data.size=request;
temp->data.state=Busy;
DuLNode *p=block_first->next;
DuLNode *q=NULL; //記錄最佳插入位置
while(p) //初始化最大空間和最佳位置
{
if(p->data.state==Free && (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.state=Busy;
return OK;
}
else
{
temp->prior=q->prior;
temp->next=q;
temp->data.address=q->data.address;
q->prior->next=temp;
q->prior=temp;
q->data.address+=request;
q->data.size=ch;
return OK;
}
return OK;
}
//主存回收
Status free(int flag)
{
DuLNode *p=block_first;
for(int i= 0; i <= flag; i++)
if(p!=NULL)
p=p->next;
else
return ERROR;
p->data.state=Free;
if(p->prior!=block_first && 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!=block_last && 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==block_last && 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";
cout<<"++++++++++++++++++++++++++++++++++++++++++++++\n\n";
DuLNode *p=block_first->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";
}
//主函式
void main()
{
int ch;//演算法選擇標記
cout<<"請輸入所使用的記憶體分配演算法:\n";
cout<<"(1)首次適應演算法\n(2)最佳適應演算法\n(3)最差適應演算法\n";
cin>>ch;
while(ch<1||ch>3)
{
cout<<"輸入錯誤,請重新輸入所使用的記憶體分配演算法:\n";
cin>>ch;
}
Initblock(); //開創空間表
int choice; //操作選擇標記
while(1)
{
show();
cout<<"請輸入您的操作:";
cout<<"\n1: 分配記憶體\n2: 回收記憶體\n0: 退出\n";
cin>>choice;
if(choice==1) alloc(ch); // 分配記憶體
else if(choice==2) // 記憶體回收
{
int flag;
cout<<"請輸入您要釋放的分割槽號:";
cin>>flag;
free(flag);
}
else if(choice==0) break; //退出
else //輸入操作有誤
{
cout<<"輸入有誤,請重試!"<<endl;
continue;
}
}
}
//3.在分頁式管理方式下采用位示圖來表示主存分配情況,實現主存空間的分配和回收。
//(1)連結串列方式:
#include <iostream>
#include <string>
using namespace std;
struct ListNode //連結串列的節點
{
int begin;
int end;
int size;
int num;
bool freeable;
ListNode *next;
};
typedef ListNode * ListPtr;
class Mem
{
public:
Mem();
void getNumStringrequest();
void getNumStringfree();
void getrequest();
void getfreerequest();
// int getNum();
//void Insert();
//void Delete();
void Print();
void freemem();
void getmem();
private:
ListPtr first;
string request;
int requestnum;
int freenum;
string freerequest;
string str;
};
Mem::Mem() //初始化,把first置為空
{
first=new ListNode;
first->next=NULL;
str="";
}
void Mem::getrequest()
{
cout<<"請輸入記憶體申請請求:"<<endl;
cin>>request;
str=str+request;
}
void Mem::getfreerequest() //每次的請求都放入str中
{
cout<<"請輸入記憶體釋放申請請求:"<<endl;
cin>>freerequest;
str=str+freerequest;
}
void Mem::getNumStringrequest()
{
int len=request.length();
string numstring=request.substr(1,len-1);
requestnum=atoi(numstring.c_str());
cout<<"申請記憶體的大小是:"<<requestnum<<endl;
}
void Mem::getNumStringfree() //使用atoi函式將char *(string通過strin.c_str())可以得到char *型別
{
int len=freerequest.length();
string freestring=freerequest.substr(5,len-2);
freenum=atoi(freestring.c_str());
cout<<"釋放記憶體的起始地址是:"<<freenum<<endl;
}
void Mem::freemem()
{
ListNode *p=first;
while(p->next!=NULL)
{
if(p->next->begin==freenum&&p->next->freeable==false)
{
cout<<"釋放記憶體!"<<p->next->num<<endl;
p->next->freeable=true;
}
ListNode *q=p->next;
if(q->freeable==true) //採用向前合併的原則
{
if(q->next!=NULL&&q->next->freeable==true&&p->freeable==true) //前後均為空
{
cout<<"釋放記憶體的前後都為空,因此將三塊記憶體合併!"<<endl; //3塊記憶體合併到最前面一塊
p->size=p->size+q->size+q->next->size;
p->freeable=true;
p->end=p->begin+p->size;
ListNode *k=q->next;
p->next=k->next;
delete q;
delete k;
}
else if(p->freeable==true&&q->next!=NULL&&q->next->freeable==false) //前為空,後面不空
{
cout<<"釋放記憶體的前一塊是空的,合併"<<endl;
p->size=p->size+q->size;
p->freeable=true;
p->end=p->begin+p->size;
p->next=q->next;
delete q;
}
else if(p->freeable==false&&q->freeable==true&&q->next->freeable==true) //前面空後面不空
{
cout<<"釋放記憶體的後一塊是空的,合併!"<<endl;
ListNode * k=q->next;
q->size=q->size+k->size;
q->freeable=true;
q->next=k->next;
q->end=q->begin+q->size;
delete k;
}
}
p=p->next;
}
}
void Mem::getmem()
{
ListNode * p=first->next;
ListNode *q;
if(p==NULL) //第一次申請記憶體
{
cout<<"第一次申請記憶體!"<<endl;
q=new ListNode;
q->begin=0;
q->freeable=false;
q->size=requestnum;
q->end=q->begin+q->size;
q->num=1;
first->next=q;
cout<<"記憶體大小:"<<q->size<<" 記憶體起始地址:"<<q->begin<<" 結束地址:"<<q->end<<" 記憶體編號:"<<q->num<<endl;
q->next=NULL;
}
else //前面有釋放的記憶體。不向後面才查詢
{
bool find=false;
p=first;
while(p->next!=NULL&&find!=true)
{
if(p->next!=NULL&&p->next->size>requestnum&&p->next->freeable==true)
{
cout<<"找到空的記憶體:"<<endl;
cout<<"記憶體大小:"<<p->next->size<<" 記憶體起始地址:"<<p->next->begin<<" 結束地址:"<<p->next->end<<" 記憶體編號:"<<p->next->num<<" 記憶體狀態:"<<p->freeable<<endl;
cout<<"將大記憶體分割:"<<endl;
ListNode *temp=p->next;
ListNode *k=new ListNode;
// k=p->next;
k->begin=p->next->begin;
k->freeable=false;
k->size=requestnum;
k->end=p->next->begin+k->size;
k->num=temp->num;
p->next=k;
ListNode *l=new ListNode;
l->begin=k->end+1;
l->size=temp->size-k->size;
l->end=l->begin+l->size;
l->freeable=true;
l->num=k->num;
l->next=temp->next;
k->next=l;
find=true;
delete temp;
}
p=p->next;
}
if(false==find) //前面沒找到合適的記憶體,因此開闢一塊新的記憶體
{
p=first;
cout<<"開闢一塊新的記憶體!"<<endl;
ListNode *q=new ListNode;
while(p->next!=NULL)
p=p->next;
q->begin=p->end+1;
q->end=q->begin+requestnum;
q->freeable=false;
q->num=p->num+1;
q->size=requestnum;
p->next=q;
q->next=NULL;
}
}
}
void Mem::Print()
{
cout<<"整個記憶體分配狀況:"<<endl;
ListNode *p=first->next;
while(p!=NULL)
{
cout<<"記憶體大小:"<<p->size<<" 記憶體起始地址:"<<p->begin<<" 記憶體末地址"<<p->end<<" 記憶體標號"<<p->num<<" 記憶體狀態"<<p->freeable<<endl;
p=p->next;
}
cout<<"申請釋放過程:"<<str<<endl;
}
int main()
{
Mem mem;
string str="";
char quit='n';
while(quit!='Y'&&quit!='y') //採用while一直迴圈實行模擬記憶體的申請與釋放
{
int chose;
cout<<" ============================================"<<endl;
cout<<" 1.記憶體申請 "<<endl;
cout<<" 2.記憶體釋放 "<<endl;
cout<<" 3.顯示記憶體狀態 (狀態0表示正在使用,不可以被釋放,狀態1表示未被使用,可以釋放"<<endl;
cout<<" 4.退出 "<<endl;
cout<<" ============================================"<<endl;
cin>>chose;
switch(chose)
{
case 1:
mem.getrequest();
mem.getNumStringrequest();
mem.getmem();
mem.Print();
break;
case 2:
mem.getfreerequest();
mem.getNumStringfree();
mem.freemem();
mem.Print();
break;
case 3:
mem.Print();
case 4: //一旦使用者選擇退出,那麼置quit為YES退出程式
quit='y';
default:
break;
}
}
/*mem.getrequest();
mem.getNumStringrequest();
mem.getmem();
mem.Print();
mem.freemem();
mem.Print();
mem.getfreerequest();
mem.getNumStringfree();
*/
return 0;
}
//(2)位示圖:
#include <stdlib.h>
#include <stdio.h>
typedef int datatype;
typedef struct node
{
datatype pageNum,blockNum;
struct node *next;
}linknode;
typedef linknode *linklist;
linklist creatlinklist(int n)/*尾插法建立帶頭結點的單鏈表*/
{
linklist head,r,s;
int x,y,i=0;
head=r=(linklist)malloc(sizeof(linknode));
printf("\n請分別輸入頁表的頁號及塊號(-1表示空):\n");
printf("\n頁號 | 塊號\n");
while (i<n)
{
scanf("%d %d",&x,&y);
s=(linklist)malloc(sizeof(linknode));
s->pageNum=x;
s->blockNum=y;
r->next=s;
r=s;
i++;
}
r->next=NULL;
return head;
}
void init(int g[100][100],int N)/*初始化位示圖,將值全置為零,0表示空閒狀態*/
{
int i,j;
for(i=0;i<100;i++)
{
for(j=0;j<100;j++)
{
g[i][j]=0; //全置為零
}
}
g[N+1][0]=N*N; //在陣列最後一個數的後面設定一個空間用來存放剩餘空閒塊數
}
linklist Init(linklist head,int g[100][100],int n,int N)
{
linklist p;
int i,j;
p=head->next;
if(n<=g[N+1][0]) //首先判斷作業的頁數是否小於等於位示圖剩餘空閒塊的個數
{
while(p)
{
i=p->blockNum/N;
j=p->blockNum%N;
g[i][j]=1;
g[N+1][0]--;
p=p->next;
}
}
return head;
}
printStr(int g[100][100],int N)/*列印位示圖*/
{
int i,j;
printf("\n此時位示圖為:\n");
printf("\n ");
for(i=0;i<N;i++)
{
printf(" ");
printf("%d",i);
}
printf("\n");
for(i=0;i<N;i++)
{
printf("%d",i);
for(j=0;j<N;j++)
{
printf(" ");
printf("%d",g[i][j]);
}
printf("\n");
}
printf("\n");
}
void print(linklist head)/*輸出帶頭結點的單鏈表*/
{
linklist p;
p=head->next;
printf("\n該頁表為:\n");
printf("\n");
printf("\n 頁號 | 塊號\n");
while(p)
{
printf("%11d%7d\n",p->pageNum,p->blockNum);
p=p->next;
}
linklist Dis(linklist head,int g[100][100],int n,int N)
{
linklist p;
int i,j;
p=head->next;
if(n<=g[N+1][0]) //首先判斷作業的頁數是否小於等於位示圖剩餘空閒塊的個數
{
while(p)
{
for(i=0;i<N;i++)
{
for(j=0;j<N;j++)
{
if(g[i][j]==0)
{
p->blockNum=N*i+j; //將對應塊號記錄到頁表
g[i][j]=1; //將塊置1,表示已被佔用
g[N+1][0]--; //剩餘空閒塊減1
break; //跳出迴圈,進行下一個頁的分配
}
}
break; //跳出迴圈
}
p=p->next; //下一個頁進行分配
}
return head;
}
}
linklist Recy(linklist head,int g[100][100],int n,int N)/*回收已經完成的頁*/
{
int i,j;
linklist p;
p=head->next;
while(p&&p->pageNum!=n) //找出要回收的頁號
{
p=p->next;
}
if(p) //找到
{
i=p->blockNum/N;
j=p->blockNum%N;
g[i][j]=0; //將該塊置0,表空閒狀態
g[N+1][0]++;
p->blockNum=-1; //頁表中對應的塊號為空,置成-1
}
return head;
}
void main()
{
int m,n,N;
int x,y,a,b,t;
int graph[100][100];
linklist head,Head;
printf("\n*****分頁式儲存管理分配及回收演算法*****\n");
printf("\n請輸入位示圖字長:");
scanf("%d",&N);
printf("\n請輸入已佔用記憶體作業的頁數:");
scanf("%d",&m);
head=creatlinklist(m);
init(graph,N);
head=Init(head,graph,m,N);
printStr(graph,N);
printf("\n當前空閒塊數為:%d",graph[N+1][0]);
printf("\n\n現在進行作業分配:\n");
printf("\n請輸入需要分配的作業的頁數:");
scanf("%d",&n);
Head=creatlinklist(n);
Head=Dis(Head,graph,n,N);
print(Head);
printStr(graph,N);
printf("\n當前空閒塊數為:%d",graph[N+1][0]);
printf("\n\n您是否想回收已完成的頁,“是”請按1,“否”請按0:");
scanf("%d",&x);
if(x) //判斷是否要回收
{
printf("\n請輸入您要回收的頁號:");
scanf("%d %d %d %d",&y,&a,&b,&t);
head=Recy(head,graph,y,N);
head=Recy(head,graph,a,N);
head=Recy(head,graph,b,N);
head=Recy(head,graph,t,N);
printStr(graph,N);
}
printf("\n當前空閒塊數為:%d",graph[N+1][0]);
printf("\n");
}
相關推薦
作業系統儲存管理實驗課程設計報告
作業系統報告 儲存管理 姓名: 鄭兆涵 專業: 電腦科學與技術(嵌入式方向) 一、設計目的、意義 本次實驗針對:(1)儲存管理實驗,(2)主儲存器空間的分配和回收實驗,兩個實驗進
C語言學生成績資訊管理系統課程設計報告
C語言課程設計報告 一 .設計目的 學生成績管理系統 主要功能: (1)能按學期、按班級完成對學生成績的錄入、 修改,刪除 (2)能按班級統計學生的成績,求學生的總分及 平均分,並能根據學生的平均成績進行排序 (3)能查詢學生成績,不及格科目及學生名單
大一java圖書館管理系統課程設計
校招 seo mos rpv p2c pen tel abd deb 各位看看我編的代碼,為啥就不能動呢??? vs2017的使用 補《歡聚時代2017校招筆試題目(PHP工程師類)---錯題解析》 區間點覆蓋CaseofFugitive:CodeForces-556
201621123063《JAVA課程設計報告》
元素 markdown 程序 pan 針對 任務 通過 remove 情況 一、需求分析 完成一個單機版的購物車 (1)先建立一個文本文件,定義出自己想要的商品。以商品編號;商品名稱;商品品牌;價格作為文件的內容,中間要求用分號或者分割 (2)編寫程序,定義一個商品類,文件
代寫COMP1001作業、代做Python程序作業、代寫Python編程作業、代做Python課程設計報告
sin radix nature oop cte compare least pri control Problem Solving Methodology in IT (COMP1001)Assignment Three(Due at noon on 11 October
代寫Digital Signal Processing作業、代做Python課程設計報告作業、代做Korotkoff作業、代寫Python語言程式作業
Assignment 1, Digital Signal Processing: Fourier TransformUniversity of GlasgowSchool of EngineeringBernd Porr2018Form groups of two, work together and sub
圖書管理系統課程設計 用Swing做UI 筆記
java Swing控制元件屬性歸納 連結: http://maloveqiao.iteye.com/blog/1668698 Java筆記(10)-圖形介面設計、Swing、視窗、JFrame、常用元件和佈局、處理事件、MVC結構、對話方塊、GUI 連結:https://blo
大學《資料庫系統》課程設計報告
湖南科技大學電腦科學與工程學院 《資料庫系統》 課 程 設 計 題 目: 教學管理系統 專 業:電腦科學與技術 年 級: 2017級 班 級: 計科三班 學 號: 170510323 姓 名: 雨 萱 完成時間:2019年1月3日 教務管理系統的分析與實現 一.實驗目的 資料庫系統課程設
《c++程式設計》課程設計報告
輸入一個百分制的成績t,將其轉換成對應的等級,具體轉換規則如下: 90~100為A; 80~89為B; 70~79為C; 60~69為D; 0~59為E; Input 輸入資料有多組,每組佔一行,由一個整陣列成。 Output 對於每組輸入資料,輸出一行。如果輸
課程設計報告
《c++程式設計》課程設計報告 班級:數學2班 &n
作業系統-儲存管理
儲存器是由記憶體和外存組成。記憶體由順序編址的塊組成,每塊包含相應的物理單元。CPU要啟動相應的輸入輸出裝置後才能使外存與記憶體交換資訊。 1、虛擬儲存器 儲存管理系統吧程序中那些不經常被訪問的程式段和資料放入外存中,待需要訪問他們時再將他們調入記憶體。對於
作業系統儲存管理之頁式儲存管理深入淺出
用分割槽方式管理的儲存器,每道程式總是要求佔用主存的一個或幾個連續儲存區域,作業或程序的大小仍受到分割槽大小或記憶體可用空間的限制,因此,有時為了接納一個新的作業而往往要移動已在主存的資訊。這不僅不方便,而且開銷不小。採用分頁儲存器既可免去移動資訊的工作,又可儘
作業系統儲存管理之分段儲存
需求 從固定分割槽到動態分割槽,從分割槽方式到分頁方式發展提高了主存空間利用率。 而分段儲存管理的引入,則滿足使用者(程式設計師)程式設計和使用上的要求,這些要求其它各種儲存管理技術難以滿足。 需求解析: 在分頁儲存管理中,經連結編輯處理得到了一維
作業系統儲存管理之分段式與段頁式虛擬儲存系統
分段式虛擬儲存系統 分段式虛擬儲存系統把作業的所有分段的副本都存放在輔助儲存器中,當作業被排程投入執行時,首先把當前需要的一段或幾段裝入主存,在執行過程中訪問到不在主存的段時再把它們裝入。因此,在段表中必須說明哪些段已在主存,存放在什麼位置,段長是多少。哪些段
學生資訊管理系統課程設計
/************************************************************************************************************************************** *
學生資訊管理系統(課程設計)
#include <iostream> #include <stdio.h> #include <stdlib.h> #include <string.h> using namespace std; struct studen
儲存管理中的設計問題
光了解Page的基本原理還不夠,還需要知道如何設計儲存才能達到一個更好的效能。 頁式儲存管理 工作集模型 在虛擬頁儲存管理中,當一個程序被啟動,其所有頁面都還在外存。當CPU取第一條指令時,就會引發缺頁中斷。因此,在程式啟動一開始,很容易發生
《面向物件程式設計》課程設計報告
題目:小型公司工資管理系統 功能: 1、公司各部門員工資訊分類錄入; 2、公司銷售部工資情況查詢;(分類各銷售經理下屬銷售員情況) 3、公司總體工資情況查詢; 要求: 實現一個工資管理系統,系統的主要功能是計算職工當月工資並要求存檔案。 公司是一個不大不小公司,職工有種
C++車輛管理系統課程設計
題目:車輛管理系統主要負責各種車輛的常規資訊管理工作。系統中的車輛主要有大客車、小轎車和卡車。每種車輛有車輛編號、車牌號、車輛製造公司、車輛購買時間、車輛型號(大客車、小轎車和卡車)、總公里數、耗油量/公里、基本維護費用、養路費、累計總費用等資訊。大客車還有載客量(最大載客數