- 姓名:倪曉東
- 學號:201821121020
- 班級: 計算1811
1. 記錄內存空間使用情況
解釋你是如何記錄內存空間使用情況,給出關鍵代碼。
/*記錄內存空間使用情況,每個進程分配到的內存塊描述*/
struct allocated_block
{
int pid;
int size; //進程大小
int start_addr; //進程分配到的內存塊的起始地址
char process_name[PROCESS_NAME_LEN]; //進程名
struct allocated_block *next; //指向下一個進程控制塊
};
2. 記錄空閑分區
用什么樣的方法記錄內存空閑區,給出關鍵代碼。
//空閑分區,描述每一個空閑塊的數據結構
struct free_block_type
{
int size; //空閑塊大小
int start_addr; //空閑塊起始位置
struct free_block_type *next; //指向下一個空閑塊
};
//指向內存中空閑塊鏈表的首地址 struct free_block_type *free_block= NULL;
空閑分區鏈表:
//按首次適配算法重新整理內存空閑塊鏈表,按空閑塊首地址排序
int rearrange_FF()
{
struct free_block_type *head= free_block;
struct free_block_type *forehand,*pre,*rear;
int i;
if(head== NULL)
return -1;
for(i= 0;i< free_block_count-1;i++)
{
forehand= head;
pre= forehand->next;
rear= pre->next;
while(pre->next!= NULL)
{
if(forehand== head&&forehand->start_addr>= pre->start_addr)
{
//比較空閑鏈表中第一個空閑塊與第二個空閑塊的開始地址的大小
head->next= pre->next;
pre->next= head;
head= pre;
forehand= head->next;
pre= forehand->next;
rear= pre->next;
}
else if(pre->start_addr>= rear->start_addr)
{
//比較鏈表中其它相鄰兩個結點的開始地址的大小
pre->next= rear->next;
forehand->next= rear;
rear->next= pre;
forehand= rear;
rear= pre->next;
}
else
{
forehand= pre;
pre= rear;
rear= rear->next;
}
}
}
return 0;
}
3. 內存分配算法
使用首次適配算法內存分配:
//按照首次適應算法給新進程分配內存空間
int allocate_FF(struct allocated_block *ab)
{
int ret;
struct free_block_type *pre= NULL,*ff= free_block;
if(ff== NULL)
return -1;
while(ff!= NULL)
{
if(ff->size>= ab->size)
{
ret= allocate(pre,ff,ab);
break;
}
pre= ff;
pre= pre->next;
}
if(ff== NULL&¤t_free_mem_size> ab->size)
ret= mem_retrench(ab);
else
ret= -2;
rearrange_FF();
return ret;
}
4. 內存釋放算法
int exit()
{
struct allocated_block *allocated_ab,*allocated_pre;
struct free_block_type *free_ab,*free_pre;
free_pre= free_block;
allocated_pre= allocated_block_head;
if(free_pre!= NULL) //鏈表不為空
{
free_ab= free_pre->next;
while(free_ab!= NULL)
{
free(free_pre); //釋放當前節點
free_pre= free_ab;
free_ab= free_ab->next; //節點后移
}
}
if(allocated_pre!= NULL)
{
allocated_ab= allocated_pre->next;
while(allocated_ab!= NULL)
{
free(allocated_pre); //釋放節點
allocated_pre= allocated_ab;
allocated_ab= allocated_ab->next; //節點后移
}
}
allocated_ab= allocated_ab->next;
return 0;
}
刪除進程,歸還分配的存儲空間,並刪除描述該進程內存分配的結點
void kill_process()
{
struct allocated_block *ab;
int pid;
printf("Kill Process,pid=");//刪除進程號為
scanf("%d",&pid);
getchar();
ab= find_process(pid); //找到pid對應的鏈表節點
if(ab!= NULL)
{
free_mem(ab); //釋放ab所表示的分配區
dispose(ab); //釋放ab數據結構結點
}
}
在進程分配鏈表中尋找指定進程:
struct allocated_block* find_process(int pid)
{
struct allocated_block *ab= allocated_block_head;
if(ab== NULL)
{
printf("不存在!\n");
return NULL;
}
while(ab->pid!= pid&&ab->next!= NULL)//查找整個鏈表
ab= ab->next;
if(ab->next== NULL&&ab->pid!= pid)//找不到
{
printf("error!\n");
return NULL;
}
return ab;
}
5. 運行結果
(1)產生測試數據
設置內存大小為1000,每次為進程分配1-100內存大小:

設置內存大小為200,每次為進程分配1-20內存大小:

(2)解釋結果

內存總大小為200,每次為進程分配1-20內存
如圖所示,創建的第一個進程號PID=1,進程名稱為PEOCESSNAME-01,內存起始地址為0,內存大小為2,空閑區首地址為2,剩余內存198。

如圖所示,創建的第二個進程號PID=2,進程名稱為PEOCESS-02,內存起始地址為2,分配到的內存大小為8,空閑區首地址為10,剩余內存190。

如圖所示,創建的第二個進程號PID=3,進程名稱為PEOCESS-03,內存起始地址為10,分配到的內存大小為15,空閑區首地址為25,剩余內存175。

如圖所示,創建的第二個進程號PID=4,進程名稱為PEOCESS-04,內存起始地址為25,分配到的內存大小為1,空閑區首地址為26,剩余內存174。
小結:
首次適配算法從空閑區的第一個表目起查找該表,把最先能夠滿足要求的空閑區分配給進程,這種方法目的在於減少查找時間。為適應這種算法,空閑區鏈中的空閑分區要按地址由低到高進行排序。該算法優先使用低址部分空閑區,在低址空間造成許多小的空閑區,在高地址空間保留大的空閑區。但是在實際使用過程中,由於優先使用低址的可用空閑區,低址部分被不斷進行分配,但又不能保證剛好完全利用,所以會留下很多不能被使用小空閑區,而且每次為進程分配內存從低址開始尋找,就要和這些小空閑區適配,會影響速率。
參考文獻:https://github.com/City-Zero/LinuxTest/blob/master/OSex/mem_manager/mm.c
