報告下載:地址。。(絕對原創,請勿抄襲)
(一)、程序功能:模擬動態分區式存貯區管理
(二)、設計思路:
1、設計一個動態分區式存貯區管理程序,支持不同的放置策略。如首次、最佳、最壞。
2、分區描述器中爲 :flag/size/next;
3、自由主存隊列按鏈表組織,主存大小假設爲maxsize(單位爲節=rd的大小)。
4、作業申請n節,實際分配的分區大小應爲n+1節。 其中一節作爲分區描述器,其他n節提供給作業。
5、已分配區放在高地址處。
6、合併時應考慮四種情況:
假設回收區爲r,上鄰爲f1(f1需搜索自由主存隊列),下鄰爲f2(f2可直接計算)
A) f1空閒,f2已分配;
B) f1已分配,f2空閒;
C) f1空閒,f2空閒;
D) f1已分配,f2已分配;
(三)、數據結構
1、PCB類(進程控制器):
私有數據成員 | |||
類型 | 名稱 | 註釋 | |
int | begin | 進程開始的首地址 | |
int | size | 進程佔用的大小 | |
string | name | 進程名 | |
函數 | |||
聲明 | 註釋 | ||
PCB(string n="無'",int s=0,int b=0) | 構造函數 | ||
ostream& operator<<(ostream&os, PCB&P) | 重定義輸出函數 |
注:PCB類是manage類的友元類。
2、block類(分區描述器):
私有數據成員 | |||
類型 | 名稱 | 註釋 | |
int | m_size | 分區的大小 | |
bool | m_falg | 判斷該分區是否被佔用 | |
block* | next | 下一個分區的地址 | |
函數 | |||
函數聲明 | 註釋 | ||
block(bool flag = false… …) | 構造函數 | ||
ostream& operator<<(ostream&os, block&P) | 重定義輸出函數 |
注:block類是manage類的友元類。
3、manage類
私有數據成員 | |||
類型 | 名稱 | 註釋 | |
block* | first; | 分區鏈表首地址 | |
vector<PCB> | lib; | 未結束的所有進程 | |
函數 | |||
聲明 | 註釋 | ||
manage() | 構造函數 | ||
void first_time(); | 首次適應算法 | ||
void best(); | 最佳適應算法 | ||
void worst(); | 最壞適應算法 | ||
void free(); | 內存回收 | ||
void show(); | 顯示內存分配情況 |
(四)、算法設計
1、首次適應算法
首次適應算法是將程序放入到主存中,按地址查找到第一個能裝入它的空閒區。在首次適應算法中,空閒區是按其位置的順序鏈接在一起,即每一個後繼空閒去的起始地址總比他前者大。當要分配一個分區時,總是從低地址空閒區開始查尋,直到找到第一個足以滿足該程序要求的空閒區爲止。
代碼:
void manage::first_time() {
cout << "輸入進程名和大小:";
string name; int size,addr(0);
cin >> name >> size;
block* p(first);
while (p != nullptr) { //尋找塊
addr +=(p->m_size+1); //計算地址
if (p->m_flag == false) { //當前塊未被佔用
if (p->m_size > size) { //當前塊的大小大於進程申請的大小
p->m_size -= (size + 1); //從當前塊中減去進程申請的大小
block* temp=new block(true,size,p->m_next); //新建一個進程塊
p->m_next = temp; //添加到當前塊的後面
addr -= (size + 1); //重新計算當前塊的地址
break;
}
else if (p->m_size == size) { //當前塊的大小剛好夠進程申請的大小
p->m_flag = true; //直接更改當前塊的狀態爲已佔用,不用分裂塊
addr -= (size + 1); //重新計算地址
break;
}
else p = p->m_next; //當前塊的大小不滿足進程申請的大小,先後繼續尋找。
}
else p = p->m_next; //當前塊已被佔用,先後繼續尋找
}
if (p == nullptr)cout << "分配失敗" << endl; //未找到符合條件的塊,分配失敗
else { //找到符合條件的塊,該進程存入lib進程庫中
PCB temp(name, size, addr);
lib.push_back(temp);
}
}
2、最佳適應算法
最佳適應算法是將程序放入主存中與他所需大小最接近的空閒區中,在最佳適應算法中,空閒區隊列是按空閒區大小遞增順序鏈接在一起的。在進行分配時總是從最小的空閒區開始查尋,因而找到的第一個能滿足要求的空閒區便是最佳的一個。即從所要求的大小來看,該區和氣候的所有空閒區相比它是最接近的。
代碼:
void manage::best() {
cout << "輸入進程名和大小:";
string name; int size, addr1(0),addr2(0);
cin >> name >> size;
block *p(first),*q(nullptr);
int Error(512);
while (p != nullptr) {
addr1 += (p->m_size + 1);
if (p->m_flag == false) { //當前塊未被佔用
if (p->m_size > size) { //當前塊的大小滿足進程請求的大小
if (p->m_size - size < Error) { //當前塊更合適該進程
Error = p->m_size - size; //計算偏差
q = p; //保存當前塊的地址
addr2 = addr1 - size - 1;
p = p->m_next; //指針後移
}
else p = p->m_next; //和之前的塊相比,之前的塊更合適該進程
}
else if (p->m_size == size) { //當前塊的大小剛好等於進程申請的大小
q = p; //已找到最合適的塊,保存當前塊的信息並退出
addr2 = addr1 - size - 1;
Error = 0;
break;
}
else p = p->m_next; //當前塊的大小小於進程請求的大小,繼續先後搜索
}
else p = p->m_next; //當前塊已經被佔用,繼續先後搜索
}
if (Error == 512)cout << "分配失敗" << endl;
else {
if (Error == 0)q->m_flag = true;
else {
q->m_size -= (size + 1); //從當前塊中減去進程申請的大小
block* temp = new block(true, size, q->m_next); //新建一個進程塊
q->m_next = temp; //添加到當前塊的後面
}
PCB temp(name, size, addr2);
lib.push_back(temp);
}
}
3、最壞適應算法
最壞適應算法就是將程序放入主存中最不適合它的空閒區,即最大的空閒區內。在最壞適應算法中,空閒區是按大小遞減順序連接到一起的,因此,其隊列指針總是指向最大空閒區,在進行分配時,總是從最大空閒區開始查尋。
代碼:
void manage::worst() {
cout << "輸入進程名和大小:";
string name; int size, addr1(0), addr2(0);
cin >> name >> size;
block *p(first), *q(nullptr);
int Error(0);
while (p != nullptr) {
addr1 += (p->m_size + 1);
if (p->m_flag == false) { //當前塊未被佔用
if (p->m_size >= size) { //當前塊的大小滿足進程請求的大小
if (p->m_size - size >= Error) {//當前塊比之前塊更大
Error = p->m_size - size; //計算偏差
q = p; //保存當前塊的地址
addr2 = addr1 - size - 1;
p = p->m_next; //指針後移
}
else p = p->m_next; //和之前的塊相比,之前的塊更合適該進程
}
else p = p->m_next; //當前塊的大小小於進程請求的大小,繼續先後搜索
}
else p = p->m_next; //當前塊已經被佔用,繼續先後搜索
}
if (Error == 0)cout << "分配失敗" << endl;
else {
q->m_size -= (size + 1); //從當前塊中減去進程申請的大小
block* temp = new block(true, size, q->m_next); //新建一個進程塊
q->m_next = temp; //添加到當前塊的後面
PCB temp1(name, size, addr2);
lib.push_back(temp1);
}
}
4、內存回收
在內存回收時應考慮四種情況:
假設回收區爲r,上鄰爲f1(f1需搜索自由主存隊列),下鄰爲f2(f2可直接計算)
A) f1空閒,f2已分配:r和f1合併
B) f1已分配,f2空閒:r和f2合併
C) f1空閒,f2空閒:r和f1、f2合併
D) f1已分配,f2已分配:r不和任何分區合併
代碼:
void manage::free() {
cout << "輸入回收進程的名稱:";
string name;
cin >> name;
//在lib庫中查找是否存在該進程
vector<PCB>::iterator it = lib.begin();
while (it != lib.end()){
if (it->name == name)
break;
else it++;
}
//該進程不存在,直接提示並退出函數
if (it == lib.end()) {
cout << "該進程不存在" << endl;
return;
}
//進程存在
else {
int addr(0); block *p(first);
while (p != nullptr) { //查找該進程所佔用的內存塊
if (it->begin == addr)break; //查找到該進程
addr += (p->m_size + 1);
p = p->m_next;
}
if (p == nullptr)cout << "未在內存中查找到該進程" << endl;
else {
p->m_flag = false; //該內存塊的狀態更改爲未佔用
//所回收的內存塊後面存在空閒的內存塊
if (p->m_next != nullptr&&p->m_next->m_flag==false) {
p->m_size += p->m_next->m_size;//該內存塊的大小增加爲爲倆內存大小之和
block *temp(p->m_next);
p->m_next = p->m_next->m_next; //更改指針指向
delete temp; //釋放後一指針的空間
}
lib.erase(it); //進程庫中刪除當前進程
//所回收的內存塊前面存在空閒的內存塊
block *q(first);
//尋找到所回收的內存塊前面的內存塊
while (q != nullptr) {
//所回收的內存塊前面存在空閒的內存塊
if (q->m_next==p&&q->m_flag == false) {
q->m_size += (p->m_size + 1);
q->m_next = p->m_next;
delete p;
break;
}
q = q->m_next;
}
}
}
}
(五)、程序運行情況
1、測試數據:初始值大小爲512(分區描述器佔一位,實際大小爲511);
2、測試結果:
(1)、首次適應算法
(2)、最佳適應算法
(3)、最差適應算法