1. 程式人生 > >模擬可變分割槽儲存管理的記憶體分配(C)

模擬可變分割槽儲存管理的記憶體分配(C)

要求:

系統根據申請者的要求,按照一定的分配策略分析記憶體空間的使用情況,找出能滿足請求的空閒區,分給申請者;當程式執行完畢或主動歸還記憶體資源時,系統要收回它所佔用的記憶體空間或它歸還的部分記憶體空間,主存分配演算法使用最壞適應分配演算法。

程式執行時根據檔案內容初始化空閒區表,檔案內容為每行兩項:起始地址 長度 中間以逗號隔開,檔案內容如下:

10,3
13,4
17,2
30,8
38,7

可變分割槽儲存管理的記憶體分配方案一般採用"已分配區表"和"空閒區表"來記錄主存已分配和未分配的情況,本例中採用單向連結串列方式來表示兩種結構。

分配記憶體時:從"空閒區表"中找出一項能滿足申請空間的記錄,然後分割該項,如果分割出剩餘空間,則將剩餘空間重新放入"空閒區表"中,同時產生一個"已分配區記錄項",該記錄的長度為申請的空間大小,起始地址為分割的"空閒區"項的起始地址。並將該記錄插入到"已分配區表"中。

回收作業記憶體時:刪除該作業在"已分配區表"中的記錄項,並按該項的地址和長度建立一個"空閒區"記錄,遍歷"空閒區表",如果存在上邊界相鄰或者下邊界相鄰的記錄項,則合併兩者(無相鄰區塊,不需要做任何操作),最後將該記錄插入到"空閒區表"中,並使之滿足降序條件。

空閒區表資料結構:

//空閒區表
struct free_link
{
	int saddr;//起始地址
	int len;//長度
	int flag;//標誌
	struct free_link *next;
};

已分配區表資料結構:
//已分配區表
struct alloc_link
{
	int saddr;//起始地址
	int len;//長度
	int work;//作業名
	struct alloc_link *next;
};

最壞適應分配演算法:

空閒區表中每個記錄項按照長度遞減的順序排列,當需要分配空間時,只需要從表中取出第一項,然後為任務分割空間即可,如果分割後有剩餘空間則將剩餘部分再次插入空閒區表中,並重新調整表中記錄項,使得滿足按照長度遞減順序。

分配記憶體流程圖:


記憶體回收流程圖:


在回收記憶體時,會涉及到回收的空閒塊可能會與"空閒區表"中的某個記錄項上邊界相鄰或者下邊界相鄰或者上下邊界都有相鄰的空閒塊,這時候就需要合併要回收的記錄塊和已有的空閒塊,本例中採用的方式是:先根據要回收的"已分配區表"中的記錄項A,生成一個地址和長度相同的空閒塊記錄B,然後遍歷"空閒區塊表",發現有上邊界相鄰的記錄項C,則修改B的起始地址為C記錄中的起始地址,長度為B塊的長度+C塊的長度,然後從連結串列中刪除記錄C,繼續遍歷,如果發現有下邊界相鄰的記錄D,則再修改C的長度為原有長度+D的記錄長度,從連結串列中再把記錄D刪除,這樣直到遍歷到連結串列尾部。此時4中不同情況都已經包含(上邊界相鄰、下邊界相鄰,上下邊界同時相鄰、無相鄰),只需要將記錄B插入到"空閒區表"中即可。

空閒塊合併核心程式碼:

        //空閒塊頭指標 
	fp = free_head;
	while(fp->next != NULL)
	{
		//上邊界相同 
		if((fp->next->saddr + fp->next->len) == fitem->saddr)
		{
			//上邊界與待回收的空間邊界進行合併 
			fitem->saddr = fp->next->saddr;
			fitem->len = fp->next->len + fitem->len;
			//釋放原有空閒塊的記憶體 
			tmp_item = fp->next;
			fp->next = tmp_item->next;
			tmp_item->next = NULL;
			free(tmp_item);
			tmp_item = NULL;
		}
		
		if((fitem->saddr + fitem->len) == fp->next->saddr)
		{
			//下邊界與待回收的空間邊界合併 
			fitem->len = fitem->len + fp->next->len;
			//釋放原有空閒塊記憶體
			tmp_item = fp->next;
			fp->next = tmp_item->next;
			tmp_item->next = NULL;
			free(tmp_item);
			tmp_item = NULL;
		}
		
		//如果已經遍歷到鏈尾則跳出 
		if(fp->next == NULL)
		{
			break;
		}
		
		fp = fp->next; 
	}
	
	//重新調整空閒區表,按空間遞減順序排列
	fp = free_head;
	while(fp->next != NULL)
	{
		if(fp->next->len <= fitem->len)
		{
			break;
		}
		fp = fp->next;
	}
	
	fitem->next = fp->next;
	fp->next = fitem;


空閒塊合併示意圖如下:


空閒區表和已分配區表在分配和回收過程中變化效果圖:


程式碼示例