專題四 存儲管理

專題四 存儲管理

一. 名詞解釋

(一)重定位技術


重定位: 邏輯地址轉變爲物理地址的過程
靜態重定位: 在目標程序裝入內存時,把程序中的指令和數據重定位
動態重定位: 在程序執行期間每次訪問內存之前進行重定位
覆蓋技術: 把程序按照自身邏輯結構,劃分爲若干功能上相對獨立的程序模塊,那些不會同時執行的模塊共享一塊內存區域
對換技術: 以程序塊爲單位,將暫時不能運行的程序塊送入外存,從而獲得內存空間


(二)分區管理技術


碎片: 在分區式內存管理系統中,在存儲分配過程當中產生的,且不能供用戶作業使用的主存裏的小分區
固定分區法: 內存中分區的個數固定不變,各個分區的大小也固定不變且每個分區只能裝入一個進程
動態分區法: 各個分區是在相應進程要進入內存時才建立的,其大小恰好適應進程大小


(三)分頁與分段技術


分頁技術: 將一個進程的邏輯地址空間劃分成若干大小相等的部分,隨後將內存劃分爲與頁面相同大小的若干存儲塊
分段技術: 將程序的地址空間按內容/函數關係劃分爲若干個段,把內存劃分與段大小相同的若干存儲塊


(四)虛擬存儲技術


快表: 在Cache中的頁表
虛擬存儲技術: 擴充邏輯地址空間,一種允許進程部分裝入內存就可以執行的技術
請求分頁: 基於分頁技術,在進程開始運行之前,將進程裝入部分頁面,根據進程運行的需要,依照某種算法淘汰某個頁面
內存抖動: 一個進程的頁面經常換入換出,花在換頁的時間遠大於進程執行的事件
工作集: 一個進程在某一小段時間 DD 內訪問頁面的集合


二. 技術比較

(一)覆蓋技術與對換技術


覆蓋技術
在這裏插入圖片描述
缺點:
程序員編程時必須劃分程序模塊和確定模塊之間的覆蓋關係,即增大編程難度

對換技術

在這裏插入圖片描述
缺點:換入換出增加了CPU的開銷(I/O設備)
比較:

覆蓋技術 交換技術
節約一個進程所需的空間 讓整個進程暫存於外存
由程序員實現覆蓋結構 無需程序員實現覆蓋結構
作業/進程內關係 整個作業/進程之間的關係

(二)分區管理技術


比較:

固定分區法 交換技術
存在內存內碎片 存在內存外碎片

三. 分頁與分段技術的地址映射

分頁技術
工作原理:
在這裏插入圖片描述
地址映射問題基本方法:
(1)明確頁的大小,以及邏輯地址
(2)計算頁號,頁號 = 邏輯地址 / 頁大小,偏移量 = 邏輯地址 % 頁大小
(3)查頁表,根據計算出來的頁表得到物理塊的起始地址,最後加上偏移量即爲物理地址

典型例題剖析:

例:某虛擬存儲器的用戶編程空間共32個頁面,每頁爲1KB,內存爲16KB。假定某時刻一用戶頁表中已調入內存的頁號和物理塊號的對照表如表所示

頁號 物理塊號
0 5
1 10
2 4
3 7

則邏輯地址0A5C(H)所對應的物理地址爲_________

解:
(1)明確頁的大小: 1KB1KB = 210B2^{10} B = 400(H)B400_{(H)} B
(2)計算頁號:A5C(H)A5C_{(H)} = 400(H)2+25C(H)400_{(H)} \cdot 2 +25C_{(H)} ,得到頁號 = 2,偏移量 = 25C(H)25C_{(H)}
(3)查頁表計算物理地址,頁號 = 2 對應的物理塊號爲 4,則物理地址的起始地址爲 400(H)4+25C(H)=125C(H)400_{(H)} \cdot 4 +25C_{(H)} = 125C_{(H)}

(2)分段技術
工作原理:
在這裏插入圖片描述
地址映射的基本方法:
(1)明確段號和段內地址
(2)查閱段表,段內地址與段表所對應的段長度相比較
(3)如果段內地址大於段長,則表示地址越界,系統發出越界中斷,中止程序終止運行,反之地址合法,將段內地址與該段的內存始址相加,得到所要訪問單元的內存地址

典型例題剖析:

例:已知段表如表所示

段號 基址 長度
0 219 600
1 2300 14
2 90 100
3 1327 580
4 1952 96

邏輯地址的物理地址是什麼?
0,430

解:
(1)明確段號: 段號 = 0,段內地址 = 430
(2)查閱段表:段長 = 600
(3)比較 段長與段內地址之間的關係,段內地址 < 段長 即合法訪問,即物理地址爲219 + 430 = 649


四. 頁面置換算法

典例剖析:
(2002 北京航空航天大學 計算機綜合改編)
已知內存大小爲2個頁面,現在給出以下訪問頁面的序列 0,0,1,1,0,3,1,2,2,4,4,3,使用FIFO算法,LRU算法,OPT算法分別計算出它們的缺頁數,以及缺頁率

(一)FIFO算法
– 算法設計思想:
(1)這種算法總是淘汰在內存中停留時間最長的一頁,即先進入內存的頁,先被換出。理由:最早調入內存的頁不再被使用的可能性要大於剛調入內存的頁
(2)規律::缺頁率隨內存塊增加而增加

– 模擬實驗過程:

// FIFO
#include<stdio.h>

/* 內存大小爲2 */
const int MAX = 2;

/* 內存初始化均爲空值NULL,s數組存放訪問的頁面的頁號 */
struct Storage
{
	int num;//存放的頁面的頁號 
	int history = 0;//初始化爲 0	
};

/* 判斷內存是否填滿 */
int IsFull(Storage* s)
{
	int i;
	for(i = 0;i<MAX;i++)
	{
		if(s[i].num == -1)//未填滿將確定首個空白處的位置,以便下一個缺頁的頁填入 
			return i;
	}
	if(i == MAX)
		return -1;//表示內存已滿 
}

/* 判斷是否需要進行頁面置換 */
bool IsChange(Storage* s,int num)
{
	int i ;
	for(i = 0;i<MAX;i++)
	{
		if(s[i].num == num)//如果在內存找到相對應的頁面則不需要置換 
			return false;
	}
	if(i == MAX)
		 return true;//在內存中未找到相對應的頁面即需要進行頁面置換 
}

/* 找到在內存時間最長的頁面*/
int LongestHistoryPosition(Storage* s)
{
	int temp = -1;
	int index = -1;
	for(int i = 0;i<MAX;i++)
	{
		if(s[i].history > temp)
		{
			temp = s[i].history;
			index = i;
		}
	}
	return index;
}
void LRU(Storage* s,int num,int& lackpage)
{
	if(IsChange(s,num))
	{
		int pd = IsFull(s);
		if(pd == -1)//內存已滿 
		{
			int index = LongestHistoryPosition(s);
			s[index].num = num;
			s[index].history = 0;
		}
		else//內存未滿 
			s[pd].num = num; 
		lackpage++;
	}
	for(int i = 0;i<MAX;i++)
	{
		if(s[i].num != -1)
			s[i].history++;
	}
		
}
int main()
{
	Storage s[MAX];
	/* 初始化內存 */
	for(int i = 0;i<MAX;i++)
		s[i].num = -1;
	int vis[12] = {0,0,1,1,0,3,1,2,2,4,4,3}; 
	int lackpage = 0;
	printf("============ 置換過程 ============\n");
	for(int i = 0;i<12;i++)
	{
		LRU(s,vis[i],lackpage);
		for(int i = 0;i<MAX;i++)
		{
			if(s[i].num == -1)
				printf("\t ");
			else
				printf("%d ",s[i].num);
		}
		printf("\n");
	}
	printf("==================================\n");
	printf("\n");
	printf("============ 統計結果 ============\n");
	double result = (double)100*((double)lackpage/(double)12);
	printf("缺頁數: %2d \n",lackpage);
	printf("缺頁率: %8f %c\n",result,'%');
	printf("==================================\n");
	
	return 0;
}

– 模擬實驗驗證結果:
在這裏插入圖片描述
(二)OPT算法

– 算法設計思想:
爲調入新頁面而必須預先淘汰掉某個老頁面時,所選擇的老頁面在將來不被使用,或者在最遠的將來才被訪問

– 模擬實驗過程:

// OPT
#include<stdio.h>

/* 內存大小爲2 */
const int MAX = 2;

/* 內存初始化均爲空值NULL,s數組存放訪問的頁面的頁號 */
struct Storage
{
	int num;//存放的頁面的頁號 
	int future = 0;//初始化爲 0	
};

/* 判斷內存是否填滿 */
int IsFull(Storage* s)
{
	int i;
	for(i = 0;i<MAX;i++)
	{
		if(s[i].num == -1)//未填滿將確定首個空白處的位置,以便下一個缺頁的頁填入 
			return i;
	}
	if(i == MAX)
		return -1;//表示內存已滿 
}

/* 判斷是否需要進行頁面置換 */
bool IsChange(Storage* s,int num)
{
	int i ;
	for(i = 0;i<MAX;i++)
	{
		if(s[i].num == num)//如果在內存找到相對應的頁面則不需要置換 
			return false;
	}
	if(i == MAX)
		 return true;//在內存中未找到相對應的頁面即需要進行頁面置換 
}

//計算內存中將來出現的時間 
void Future(Storage* s,int* vis,int position)
{
	for(int i = 0;i<MAX;i++)
	{
		for(int j = position+1;vis[j] != s[i].num;j++)
			s[i].future++;
	}
}

//找出內存中將來出現的時間最大的頁面 
int MaxFuture(Storage* s)
{
	int index = -1;
	int temp = -1;
	for(int i = 0;i<MAX;i++)
	{
		if(s[i].future > temp)
		{
			temp = s[i].future;
			index = i;
		}
	}
	return index;
}

void OPT(Storage* s,int num,int& lackpage,int * vis,int position)
{
	if(IsChange(s,num))
	{
		int pd = IsFull(s);
		if(pd == -1)//內存已滿 
		{
			Future(s,vis,position);
			int index = MaxFuture(s);
			s[index].future = 0;
			s[index].num = num;
		}
		else//內存未滿 
			s[pd].num = num; 
		lackpage++;
	}
	for(int i = 0;i<MAX;i++)
	{
		if(s[i].num != -1)
			s[i].future++;
	}
		
}
int main()
{
	Storage s[MAX];
	/* 初始化內存 */
	for(int i = 0;i<MAX;i++)
		s[i].num = -1;
	int vis[12] = {0,0,1,1,0,3,1,2,2,4,4,3}; 
	int lackpage = 0;
	printf("============ 置換過程 ============\n");
	for(int i = 0;i<12;i++)
	{
		OPT(s,vis[i],lackpage,vis,i);
		for(int i = 0;i<MAX;i++)
		{
			if(s[i].num == -1)
				printf("\t ");
			else
				printf("%d ",s[i].num);
		}
		printf("\n");
	}
	printf("==================================\n");
	printf("\n");
	printf("============ 統計結果 ============\n");
	double result = (double)100*((double)lackpage/(double)12);
	printf("缺頁數: %2d \n",lackpage);
	printf("缺頁率: %8f %c\n",result,'%');
	printf("==================================\n");
	
	return 0;
}

– 模擬實驗驗證結果:
在這裏插入圖片描述
(三)LRU算法

– 算法設計思想:
將“最近的過去”作爲“不久的將來”的近似,就可以把最近一段時間裏不曾使用的頁面淘汰掉,即實質上:當需要置換一頁時,選擇在最近一段時間裏不曾使用的頁面淘汰掉

– 模擬實驗過程

// LRU
#include<stdio.h>

/* 內存大小爲2 */
const int MAX = 2;

const int MAXN = 999;

/* 內存初始化均爲空值NULL,s數組存放訪問的頁面的頁號 */
struct Storage
{
	int num;//存放的頁面的頁號 
	int history = 0;//初始化爲 0	
};

/* 判斷內存是否填滿 */
int IsFull(Storage* s)
{
	int i;
	for(i = 0;i<MAX;i++)
	{
		if(s[i].num == -1)//未填滿將確定首個空白處的位置,以便下一個缺頁的頁填入 
			return i;
	}
	if(i == MAX)
		return -1;//表示內存已滿 
}

/* 判斷是否需要進行頁面置換 */
bool IsChange(Storage* s,int num)
{
	int i ;
	for(i = 0;i<MAX;i++)
	{
		if(s[i].num == num)//如果在內存找到相對應的頁面則不需要置換 
			return false;
	}
	if(i == MAX)
		 return true;//在內存中未找到相對應的頁面即需要進行頁面置換 
}

/* 找到在內存時間最長的頁面*/
int ShortestHistoryPosition(Storage* s)
{
	int temp = MAXN;
	int index = -1;
	for(int i = 0;i<MAX;i++)
	{
		if(s[i].history < temp)
		{
			temp = s[i].history;
			index = i;
		}
	}
	return index;
}

void LRU(Storage* s,int num,int& lackpage)
{
	if(IsChange(s,num))
	{
		int pd = IsFull(s);
		if(pd == -1)//內存已滿 
		{
			int index = ShortestHistoryPosition(s);
			s[index].num = num;
			s[index].history = 0;
		}
		else//內存未滿 
			s[pd].num = num; 
		lackpage++;
	}
	for(int i = 0;i<MAX;i++)
	{
		if(s[i].num != -1)
			s[i].history++;
	}
		
}
int main()
{
	Storage s[MAX];
	/* 初始化內存 */
	for(int i = 0;i<MAX;i++)
		s[i].num = -1;
	int vis[12] = {0,0,1,1,0,3,1,2,2,4,4,3}; 
	int lackpage = 0;
	printf("============ 置換過程 ============\n");
	for(int i = 0;i<12;i++)
	{
		LRU(s,vis[i],lackpage);
		for(int i = 0;i<MAX;i++)
		{
			if(s[i].num == -1)
				printf("\t ");
			else
				printf("%d ",s[i].num);
		}
		printf("\n");
	}
	printf("\n");
	printf("============ 統計結果 ============\n");
	double result = (double)100*((double)lackpage/(double)12);
	printf("缺頁數: %2d \n",lackpage);
	printf("缺頁率: %8f %c",result,'%');
	
	return 0;
}

– 模擬實驗驗證結果:
在這裏插入圖片描述

參考文獻

[1] 操作系統原理 機械工業出版社 第二版 孟慶昌 張志華
[2] 參考慕課:西安交通大學 軟件學院 田麗華(副教授)

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章