1. 程式人生 > >記憶體分配演算法-(首次分配法和最佳分配法)

記憶體分配演算法-(首次分配法和最佳分配法)

/* implement a memory allocation scheme by using algorithms first-fit, next-fit, and best-fit
 * freelist為空閒區連結串列的頭,它的下一個節點才指向空閒緩衝區
 * freelist是按首地址來排序的,而不是按size來排序。按首地址排序便於相鄰空閒記憶體合併;按size大小來排序,便於分配記憶體
 */
#include<stdio.h>
#include<stdlib.h>

#define N 	100

typedef enum {FALSE, TRUE} bool;

typedef struct node
{
	char *ptr; //start addr 指向mem處開始的地址
	int size; //size of the free block
	struct node *next; //next free block
}node;

char mem[N]; //total memory pool
node freelist; //head of free list, no value

/* init freelist to contain the whole mem */
void init()
{
	node *ptr = (node *)malloc(sizeof(node));
	ptr->ptr = mem;
	ptr->size = N;
	ptr->next = NULL;
	freelist.next = ptr;
}

/* remove a node ptr from the list whose previous node is prev */
void removenode(node *ptr, node *prev)
{	
	prev->next = ptr->next;
	free(ptr);
}

/* 首次適配法:從自由空閒區中選取第一個合適空閒區來分配 
 * 返回分配記憶體區首地址
 */
char *firstfit(int size) 
{
	node *ptr, *prev;
	char *memptr;
	
	for(prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next)
		if(ptr->size > size)
		{
			memptr = ptr->ptr;
			ptr->size -= size; //從空閒區去掉size空間
			ptr->ptr += size; //空閒區首地址往後移size個單位
			return memptr; //返回申請到的空閒區 首地址
		}
		else if(ptr->size = size)
		{
			memptr = ptr->ptr;
			removenode(ptr, prev);
			return memptr;
		}
	return NULL; //沒有足夠長的空閒記憶體
}

/* 最佳適配法:找到大小與size最接近的空閒區來分配 */
char *bestfit(int size)
{
	node *ptr, *prev;
	char *memptr;
	int minwaste = N+1;
	node *minptr = NULL, *minprev;
	
	for(prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next)
		if(ptr->size >= size && ptr->size-size < minwaste)
		{
			minwaste = ptr->size - size;
			minptr = ptr;
			minprev = prev;
		}
	if(minptr == NULL)//沒有找到
		return NULL;
	ptr = minptr;
	prev = minptr;
	if(ptr->size > size)
	{
		memptr = ptr->ptr;
		ptr->size -= size;
		ptr->ptr += size;
		return memptr;
	}
	else if(ptr->size == size)
	{
		memptr = ptr->ptr;
		removenode(ptr, prev);
		return memptr;
	}
	return NULL;
}

/* add memptr of size to freelist, remember that block ptrs are stored on mem addr */
void addtofreelist(char *memptr, int size)
{
	node *prev, *ptr, *newptr;
	
	for(prev=&freelist, ptr=prev->next; ptr && ptr->ptr < memptr; prev=ptr, ptr=ptr->next)
		;
	newptr = (node *)malloc(sizeof(node));
	newptr->ptr = memptr;
	newptr->size = size;
	newptr->next = ptr;
	prev->next = newptr;
}

/* combine adj blocks of list if necessary */
void coalesce()
{
	node *prev, *ptr;
	
	for(prev=&freelist, ptr=prev->next; ptr; prev=ptr, ptr=ptr->next)
		if(prev != &freelist && prev->ptr+prev->size == ptr->ptr)
		{
			prev->next = ptr->next;
			free(ptr);
			ptr = prev;
		}
}

/* prt: sizeof(int) contains size of the pool allocated 
 * 返回分配的空間首地址(不包括最前面的長度的4個位元組)
 */
char *memalloc(int size)
{
	char *ptr = firstfit(size + sizeof(int)); //此處選擇分配演算法
	printf("allocating %d using firstfit...\n", size);
	if(ptr == NULL)
		return NULL;
	*(int *)ptr = size; //分配的空閒記憶體區前面幾個位元組用於存放分配數
	return ptr+sizeof(int);
}

void memfree(char *ptr)
{
	int size = *(int *)(ptr-sizeof(int));//找到已分配的空閒區大小(空閒區的前4個位元組)
	printf("freeing %d...\n", size);
	addtofreelist(ptr-sizeof(int), size+sizeof(int));
	coalesce();
}

void printfreelist()
{
	node *ptr;
	printf("\t");
	for(ptr=freelist.next; ptr; ptr=ptr->next)
		printf("{%u %d}", ptr->ptr, ptr->size);
	putchar('\n');
}

main()
{
	char *p1, *p2, *p3, *p4, *p5;
	init();
	printfreelist();
	
	p1 = memalloc(10);//note:分配10個位元組,但其前面還有4個位元組用於指示長度的,所以共用了14位元組
	printfreelist();
	p2 = memalloc(15);
	printfreelist();
	p3 = memalloc(23);
	printfreelist();
	p4 = memalloc(3);
	printfreelist();
	p5 = memalloc(8);
	printfreelist();
	memfree(p1);
	printfreelist();
	memfree(p5);
	printfreelist();
	memfree(p3);
	printfreelist();
	p1 = memalloc(23);
	printfreelist();
	p1 = memalloc(23);
	printfreelist();
	memfree(p2);
	printfreelist();
	p1 = memalloc(3);
	printfreelist();
	memfree(p4);
	printfreelist();
	p2 = memalloc(1);
	printfreelist();
	memfree(p1);
	printfreelist();
	memfree(p2);
	printfreelist();
	return 0;
	
}