可变分区存储管理,又称动态分区模式,是实存管理中连续存储的一种实现方式。
在分区的分配和回收时,根据不同的查找规则,有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的起始地址。