可變分割槽儲存管理(最先、下次、最佳、最差適配法)
阿新 • • 發佈:2019-02-11
可變分割槽儲存管理,又稱動態分割槽模式,是實存管理中連續儲存的一種實現方式。
在分割槽的分配和回收時,根據不同的查詢規則,有5種:
- first fit,最先適應分配演算法,按地址遞增排序。
- next fit,下次適應分配演算法,在first fit基礎上,從上次搜尋結束為止開始搜尋。
- best fit,最佳適應分配演算法,按空閒區長度從大到小排序。
- worst fit,最壞適應分配演算法,按空閒區長度遞減排序。
- quick fit,快速適應分配演算法,將常用長度的空閒區有組織地存放。
這裡以一份程式碼來演示最先適配法,下次適配法,最佳和最差適配法。原始檔命名為variable_partition.c
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//#define JOB_MAX 10
struct
{
int address;
int length;
int id;
}used_table[JOB_MAX];
struct f_table
{
int address;
int length;
}free_table[JOB_MAX+1];
int free_num = 1;
int used_num = 0;
int comp_addr_increase(const void *p1 , const void *p2)
{
return ((struct f_table*)p1)->address - ((struct f_table*)p2)->address;
}
int comp_length_increase(const void *p1, const void *p2)
{
return ((struct f_table*)p1)->length - ((struct f_table*)p2)->length;
}
int comp_length_decrease(const void *p1, const void *p2 )
{
return ((struct f_table*)p2)->length - ((struct f_table*)p1)->length;
}
int update_free_table()
{
int i, j;
if(free_num < 2)
return 0;
/* sort by address */
qsort(free_table, free_num, sizeof free_table[0], comp_addr_increase);
/* merge */
for(i=0; i < free_num-1; i ++)
{
if(free_table[i].address + free_table[i].length == free_table[i+1].address)
{
free_table[i].length += free_table[i+1].length;
for(j = i+1; j < free_num-1; j ++)
{
memcpy(&free_table[j], &free_table[j+1], sizeof free_table[0]);
}
free_num --;
i --;
}
}
/* sort by length if necessary */
#if defined( BEST_FIT )
qsort(free_table, free_num, sizeof free_table[0], comp_length_increase);
#elif defined( WORST_FIT )
qsort(free_table, free_num, sizeof free_table[0], comp_length_decrease);
#endif
return 0;
}
int show()
{
int i=0;
printf(".-----------------------------------\n");
printf("| free table:\n");
if(free_num)
{
printf("|%10s %10s\n", "Address", "Length");
for(i=0; i<free_num; i ++)
{
printf("|%10d %10d\n", free_table[i].address, free_table[i].length);
}
}
else
{
printf("| no free table now!\n");
}
printf("|-----------------------------------\n");
printf("| used table:\n");
if(used_num)
{
printf("|%10s %10s %5s\n", "Address", "Length","pid");
for(i=0; i<used_num; i ++)
{
printf("|%10d %10d %5d\n", used_table[i].address, \
used_table[i].length, used_table[i].id);
}
}
else
{
printf("|No job running now!\n");
}
printf(".-----------------------------------\n");
return 0;
}
/* return task id if no error
* return -1 if no space for new task
*/
int allocate(int size)
{
static int next_pid = 1;
static int next_fit_pos = 0;
int n;
int i;
if(used_num >= JOB_MAX || free_num < 1)
return -1;
#if defined( NEXT_FIT )
for(i = (next_fit_pos+1)%free_num, n = free_num; \
n > 0; \
i = (i+1)%free_num, n--)
#else
for(i= 0; i<free_num; i ++)
#endif
{
if(size <= free_table[i].length)
{
used_table[used_num].id = next_pid ++;
used_table[used_num].address = free_table[i].address;
used_table[used_num].length = size;
free_table[i].address += size;
free_table[i].length -= size;
#if defined( NEXT_FIT )
next_fit_pos = i;
#endif
if(0 == free_table[i].length)
{
/* delete this free item */
for(; i<free_num; i ++)
{
memcpy(&free_table[i], &free_table[i+1], sizeof free_table[0]);
}
free_num --;
}
used_num ++;
update_free_table();
return next_pid-1;
}
}
/* no enough size */
return -1;
}
/*
* return -1 if no such job
* return 0 if no error
*/
int reclaim(int pid)
{
int i;
if(0 == used_num)
return -1;
for(i=0; i < used_num; i ++)
{
if(used_table[i].id == pid)
{
free_table[free_num].address = used_table[i].address;
free_table[free_num].length = used_table[i].length;
free_num ++;
update_free_table();
for(; i< used_num; i ++)
{
memcpy(&used_table[i], &used_table[i+1], sizeof used_table[0]);
}
used_num --;
return 0;
}
}
return -1;
}
int main()
{
int input = 0;
int pid;
int size;
int ret;
free_table[0].address = 40000;
free_table[0].length = 1000;
show();
while(1)
{
printf("0-quit 1-allocate 2-reclaim input:");
fflush(stdout);
scanf("%d", &input);
switch(input)
{
case 0:
exit(1);
case 1:
printf("please input task size:");
fflush(stdout);
scanf("%d", &size);
pid = allocate(size);
if(pid > 0)
{
printf("job #%d is running\n", pid);
show();
}
else
{
printf("job cannot run\n");
}
break;
case 2:
printf("please input the task id:");
fflush(stdout);
scanf("%d", &pid);
ret = reclaim(pid);
if(ret)
{
printf("no such job\n");
}
else
{
printf("job #%d reclaimed.\n", pid);
show();
}
break;
default:
printf("no such choice\n");
}
}
return 0;
}
對應的Makefile如下:
SOURCE_FILES = variable_partition.c
N=100
all:f n b w
f: $(SOURCE_FILES)
gcc $(SOURCE_FILES) -o firstfit -DJOB_MAX=$N
n: $(SOURCE_FILES)
gcc $(SOURCE_FILES) -o nextfit -DNEXT_FIT -DJOB_MAX=$N
b: $(SOURCE_FILES)
gcc $(SOURCE_FILES) -o bestfit -DBEST_FIT -DJOB_MAX=$N
w: $(SOURCE_FILES)
gcc $(SOURCE_FILES) -o worstfit -DWORST_FIT -DJOB_MAX=$N
clean:
rm -f firstfit nextfit bestfit worstfit
需要說明的是,用陣列來儲存空閒區和非空閒區,在next fit中,由於遍歷的位置記錄的是空閒區的陣列下標,所以當新空閒區插入時,會從新插入的分割槽開始遍歷。如果想要嚴格地實現“從上次遍歷結束得位置”開始搜尋,可以記錄下空閒區起始地址,然後通過地址來判斷next fit的起始地址。