**
web
<svg xmlns="http://www.w3.org/2000/svg" style="display: none;"><path stroke-linecap="round" d="M5,0 0,2.5 5,5z" id="raphael-marker-block" style="-webkit-tap-highlight-color: rgba(0, 0, 0, 0);"></path></svg> <h2><a id="_0" target="_blank"></a>內存管理</h2>
設計程序模擬內存的動態分區內存管理方法。內存空閒區使用空閒分區表進行管理,採用最早適應算法從空閒分區表中尋找空閒區進行分配,內存回收時不考慮與相鄰空閒區的合併。
假定系統的內存共640K,初始狀態爲操做系統自己佔用40K。算法
t1 時刻,爲做業A、B、C分配80K、60K、100K、的內存空間;
t2 時刻做業B完成;
t3 時刻爲做業D分配50K的內存空間;
t4 時刻做業C、A完成;
t5 時刻做業D完成。編程
要求編程序分別輸出t一、t二、t三、t四、t5時刻內存的空閒區的狀態。markdown
流程圖:
數據結構
數據結構定義:
//進程PCB類型的描述
struct PCB
{
char name; //進程名
int address; //進程分區起止
int len; //進程所佔分區長度
};
struct PCB PCBelem[maxPCB];//進程佔用內存表
//分區類型的描述
struct Part
{
int address; //空閒分區起始地址
int len; //空閒分區大小
};
struct Part Partelem[maxPart]; //空閒分區表svg
主要變量說明:
int length = 640 ; //系統有 640 KB 的空閒
int fnum = 0; //記錄總的分區數量
int jnum = 0; //記錄總的進程數量
int leng = 0; //臨時變量函數
函數說明:
void init4IOS(int tem) //爲操做系統分配40k內存
int getTagByPcb(char name) //斷定輸入的進程是否存在以及位置
void request() //進程分配請求
void getPrint() //打印空閒分區
void jcPrintf() //打印進程
void release() //回收指定進程內存優化
關鍵點敘述:atom
(1) 內存結構的創建及表示
分別創建進程佔用內存表和空閒分區表,因爲進程和空閒分區的全部屬性值不同,因此須要分別建表,它們之間起始地址是連續的,邏輯上造成一整塊內存。操作系統
(2) 進程請求分配
當進程提出內存分配請求之後,首先須要作的是在空閒分區表當中尋找一個單獨的,足夠請求進程分配的內存空間。注意,尋求該空間須要從內存低址開始尋找,這樣有利於保護高址大塊內存,固然,缺點就是會產生較多的碎片內存,這些內存難以被利用。(本程序未涉及相鄰空閒空間的合併,以及內存空間的緊湊)若存在這樣一個空間,則從該空間當中劃出請求進程所需的內存大小,將該內存塊(含有起始地址等信息的結構體結點)存入進程佔用內存表當中,同時,對於被劃分的內存空間,須要修改其起始地址,達到邏輯上的合理。值得一提的是,若內存分配之後,被劃份內存空間大小爲0,則須要除去該條記錄(移除(覆蓋)空閒分區表)。
(3)回收進程
當對指定進程提出回收要求時,會產生兩個反應,一是會對空閒分區表插入一塊內存,用以表示被回收內存的空閒已空閒出來;二是對於被回收的進程,不該該出如今進程佔用表當中,因此應當將其移除進程佔用表。
對於以上兩個操做的實現:對空閒分區表插入空閒內存時,須要從高址內存空間開始對比插入內存空間的大小,當出現內存空間的起始地址小於插入內存空間的起始地址時中止對比查找,將其後的內存空間均向後移動一位,以騰出一個位置用於插入須要插入的空閒內存空間,這樣在物理結構上也就合理了。除去被回收的進程,思想與上相似,找到該進程之後,將該進程之後的結點均向前移動一位,末尾指向相應減一,除去被回收的進程目的在於避免對同一進程進行重複回收。
存在問題:
模擬內存管理所實現效果簡單,與真實內存分配存在很大差別。
改進:
(1) 實現相鄰空閒空間的合併
(2) 內存空間緊湊
(3) 其餘優化
我的總結:
一、 本程序編寫完成之後,初步理解內存管理過程。程序實現的功能較爲簡單,沒有考慮相鄰空閒分區的合併,以及碎片空間的緊湊整理等操做。
二、越努力,越幸運!_
程序效果圖(部分):
完整代碼:
#include "stdio.h" #include "Windows.h" #define maxPCB 100 //定義最大PCB結點數 #define maxPart 100 //定義最大分區 //進程PCB類型的描述 struct PCB { char name; //進程名 int address; //進程分區起止 int len; //進程所佔分區長度 }; struct PCB PCBelem[maxPCB];//進程佔用內存表 //分區類型的描述 struct Part { int address; //空閒分區起始地址 int len; //空閒分區大小 }; struct Part Partelem[maxPart];//空閒分區表 int length = 640 ; //系統有 640 KB 的空閒 int fnum = 0; //記錄總的分區數量 int jnum = 0; //記錄總的進程數量 struct Part part; //公共使用臨時結點(分區) struct PCB pcb; //公共使用臨時結點(進程) //爲操做系統分配40k內存 void init4IOS(int tem) { length = length - tem; //剩餘系統空閒空間減小 part.address = 0 + 40; //操做系統佔用,空閒內存從40開始 part.len = length; //空閒內存大小 Partelem[fnum] = part; //存入空閒分區表 fnum ++; //分區數增長 } //斷定輸入的進程是否存在以及位置 int getTagByPcb(char name) { int i; for(i = 0; i < jnum; i ++) { if(name == PCBelem[i].name) { return i; } } printf("\n\t\t找不到進程名%c,請從新輸入!\n",name); return -1; } //進程分配請求 void request() { char c = 0; while(true) { printf("\n\t\t請輸入請求內存進程 名稱:"); fflush(stdin);//清空緩衝區 scanf("%c",&pcb.name); //檢查是否已存在進程 for(int j = 0; j < jnum; j++) { if(PCBelem[j].name == pcb.name) { printf("\n\t\t進程 %c 已存在,可嘗試輸入其餘名稱,也能夠先回收該進程!\n",pcb.name); return; } } printf("\n\t\t\t\t 長度:"); fflush(stdin);//清空緩衝區 scanf("%d",&pcb.len); length = length - pcb.len; //減去相對應的操做系統剩餘空閒空間 if(length <= 0) { if(length == 0) { printf("\n\t\t警告:系統資源已經所有分配!\n"); } else { length = length + pcb.len; //分配失敗將內存換回去,以避免溢出 printf("\n\t\t未找到合適空間或者系統資源不足!\n"); return; } } //若是符合分配條件,進行分配 for(int i = 0; i < fnum; i++) { //尋找一個能夠分配的空間 if(pcb.len <= Partelem[i].len) { //改變進程佔用地址 pcb.address = Partelem[i].address; //保存該進程 PCBelem[jnum++] = pcb; //對空閒分區進行劃分 Partelem[i].address = Partelem[i].address + pcb.len; Partelem[i].len = Partelem[i].len - pcb.len; break;//關鍵做用(從低址找到一個空間就能夠了,不必再日後找了) } } //除去分配後空閒空間爲0的記錄 if(Partelem[i].len == 0) { int leng = i; //進行前移覆蓋 while(leng != fnum) { part.address = Partelem[leng+1].address; part.len = Partelem[leng+1].len; Partelem[leng] = part; leng++; } //分區數減小 fnum--; } printf("\n\t\t是否要繼續輸入進程?(Y/y) 是/(N/n) 否:"); fflush(stdin); c = getchar(); fflush(stdin); if(c=='N'||c=='n') { break; } } } //打印空閒分區 void getPrint() { printf("\t\t----------------------空閒分區 begin----------------------\n"); int j = 1; for (int i = 0;i < fnum; i ++) { printf("\n\t\t第%d塊空閒內存 起始地址爲%d,容量爲%d\n",j,Partelem[i].address,Partelem[i].len); j ++; } printf("\n\t\t----------------------空閒分區 end ----------------------\n"); } //打印進程 void jcPrintf() { printf("\n\t\t名稱\t起始地址\t大小\n"); for(int i = 0 ; i < jnum; i++) { printf("\n\t\t%2c\t%4d\t\t%d KB\n",PCBelem[i].name,PCBelem[i].address,PCBelem[i].len); } } //回收指定進程內存 void release() { int i = 0; char name; printf("\n\t\t請輸入想要回收的進程名稱:"); fflush(stdin);//清空緩衝區 scanf("%c",&name); if(getTagByPcb(name) == -1) { printf("\n\t\t該進程不存在或者已經被回收!\n"); return; } printf("\n\t\t正在回收%c的內存:",name); for(int j = 0; j < 15; j++) { printf("▊"); Sleep(200); } printf(" 完成 \n"); //for循環尋找該進程 for(i = fnum; i >= 0; i --) { int leng = fnum; if(PCBelem[getTagByPcb(name)].address > Partelem[i-1].address || i == 0) { //while循環爲該進程騰出一個位置 while(leng != i) { part.address = Partelem[leng-1].address; part.len = Partelem[leng-1].len; Partelem[leng] = part; leng--; } break;//關鍵(從高址往前找到一個空間就能夠了,不必再往前找了) } } //系統空閒空間對應增長 length = length + PCBelem[getTagByPcb(name)].len; //使用公共的結點記錄即將產生的空閒空間 part.address = PCBelem[getTagByPcb(name)].address; part.len = PCBelem[getTagByPcb(name)].len; //將該結點存入以前騰出的位置 Partelem[i] = part; //分區數增長 fnum ++; //對進程佔用內存表進行調整,除去被回收進程 int leng = getTagByPcb(name); //進行前移覆蓋 while(leng != jnum) { pcb.name = PCBelem[leng+1].name; pcb.address = PCBelem[leng+1].address; pcb.len = PCBelem[leng+1].len; PCBelem[leng] = pcb; leng++; } //進程數減小 jnum--; } void main() { char tem = 0; int OSsize = 40; int b = 1, k; //爲操做系統分配內存 init4IOS(OSsize); while (b) { system("cls"); printf("\n\n\t\t操做系統內存分配\n\n"); printf("\t\t已爲操做系統分配了 40 KB 內存\n",tem); printf("\n\t\t ----------------------------\n"); printf("\t\t|1.... 請求分配內存 |\n"); printf("\t\t|2.... 輸出空閒分區 |\n"); printf("\t\t|3.... 強制進程結束 |\n"); printf("\t\t|4.... 輸出進程信息 |\n"); printf("\t\t|0.... 退出 |\n"); printf("\t\t ----------------------------\n\n"); printf("\t\t當前操做系統空閒內存:%d KB\n",length); printf("\n\t\t請選擇:"); scanf("%d", &k); switch (k) { case 1: request(); break; case 2: getPrint(); break; case 3: release(); break; case 4: jcPrintf(); break; case 0: b = 0; break; } if (b != 0) { printf("\n\t\t"); system("pause"); } } }
若有錯誤,歡迎指正!