姓名:李瑶
学号:201821121002
班级:计算1811
1. 记录内存空间使用情况
需要定义一个结构体allocated_block,表示每个进程分配到的内存块描述:
包括进程标识符、进程大小等,当释放进程内存时,就将成功释放的进程块节点从链表中删除。
/*每个进程分配到的内存块描述*/ typedef struct allocated_block{ int pid; int size; int start_addr; char process_name[PROCESS_NAME_LEN]; struct allocated_block *next; }AB;
2. 记录空闲分区
需要定义一个结构体free_block_type描述每一个空闲块的数据结构:
包括空闲块大小、空闲块起始地址等。
由于使用首次适应算法,要从空闲分区表的第一个表目起查找该表,把最先能够满足要求的空闲区分配给作业,这种方法的目的在于减少查找时间
/*描述每一个空闲块的数据结构*/ typedef struct free_block_type{ int size; int start_addr; struct free_block_type *next; }FBT;
3.内存分配算法
这种策略旨在从最低地址的空闲分区开始找起,找到合适的便进行分配。内存空间按起始地址从小到大排序。
void do_allocate_mem(AB *ab){ int request = ab->size; FBT *tmp = free_block; while(tmp != NULL){ if(tmp->size >= request){ //分配 ab->start_addr = tmp->start_addr; int shengyu = tmp->size - request; if(shengyu <= min_mem_size){ //剩余过小全部分配 ab->size = tmp->size; if(tmp == free_block){ free_block = free_block->next; free(tmp); }else{ FBT *t = free_block; while(t->next != tmp){ t = t->next; } t->next = tmp->next; free(tmp); } }else{ //切割出分配走的内存 tmp->size = shengyu; tmp->start_addr = tmp->start_addr + request; } return ; } tmp = tmp->next; } } void rearrange_FF(){ /*首次适应算法,空闲区大小按起始地址升序排序*/ //这里使用冒泡排序方法 if(free_block == NULL || free_block->next == NULL) return; FBT *t1,*t2,*head; head = free_block; for(t1 = head->next;t1;t1 = t1->next){ for(t2 = head;t2 != t1;t2=t2->next){ if(t2->start_addr > t2->next->start_addr){ int tmp = t2->start_addr; t2->start_addr = t2->next->start_addr; t2->next->start_addr = tmp; tmp = t2->size; t2->size = t2->next->size; t2->next->size = tmp; } } } }
4. 内存释放算法
//释放链表节点 int dispose(AB *free_ab){ /*释放ab数据结构节点*/ AB *pre,*ab; if(free_ab == allocated_block_head){ //如果要是释放第一个节点 allocated_block_head = allocated_block_head->next; free(free_ab); return 1; } pre = allocated_block_head; ab = allocated_block_head->next; while(ab!=free_ab){ pre = ab; ab = ab->next; } pre->next = ab->next; free(ab); return 2; } int free_mem(AB *ab){ /* 将ab所表示的已分配区归还,并进行可能的合并 */ int algorithm = ma_algorithm; FBT *fbt,*pre,*work; fbt = (FBT*)malloc(sizeof(FBT)); if(!fbt) return -1; /* fbt->size = ab->size; fbt->start_addr = ab->start_addr; //插至末尾 work = free_block; if(work == NULL){ free_block = fbt; fbt->next == NULL; }else{ while(work ->next != NULL){ work = work->next; } fbt->next = work->next; work->next = fbt; } //按地址重新排布 rearrange_FF(); //合并可能分区;即若两空闲分区相连则合并 pre = free_block; while(pre->next){ work = pre->next; if(pre->start_addr + pre->size == work->start_addr ){ pre->size = pre->size + work->size; pre->next = work->next; free(work); continue; }else{ pre = pre->next; } } //按照当前算法排序 rearrange(ma_algorithm); return 1; } int kill_process(){ AB *ab; int pid; printf("Kill Process,pid="); scanf("%d",&pid); ab = find_process(pid); if(ab!=NULL){ free_mem(ab); //释放ab所表示的分配表 dispose(ab); //释放ab数据结构节点 return 0; }else{ return -1; } }
5. 运行结果
产生测试结果:
int main(int argc, char const *argv[]){
/* code */
int sel1,sel2;
int total=0; //记录分配内存的次数
free_block = init_free_block(mem_size); //初始化空闲区
Prc prc[PROCESS_NUM];//存放要加载的进程
init_program(prc,PROCESS_NUM);//对这几个程进程进行初始化
srand( (unsigned)time( NULL ) );
for(int i=0;i<DATA_NUM;++i)
{
/*
sel1=0表示为某进程分配内存空间
sel1=1表示为释放某进程占用的内存空间
*/
sel1=rand()%2;
int count=0;
//统计三个进程中有多少个进程已经分配内存
for(int j=0;j<PROCESS_NUM;++j){
if(prc[j].pid!=-1)
count++;
}
//如果全部分配进程或者进程分配到达10次,那么就不能继续分配内存
if((count==PROCESS_NUM && sel1==0)||total==10)
sel1=1;
//如果全部未分配进程,那么就不能继续释放内存
if(count==0 && sel1==1)
sel1=0;
if(sel1==0)//为进程分配内存
{
//随机找到一个未分配内存的进程
do{
sel2=rand()%PROCESS_NUM;
}while(prc[sel2].pid!=-1);
alloc_process(prc[sel2]);//分配内存空间
prc[sel2].pid=pid;//改变标记
total++;
display_mem_usage();//显示
}
else//释放进程占用的内存空间
{
//随机找到一个可释放进程
do{
sel2=rand()%PROCESS_NUM;
}while(prc[sel2].pid==-1);
kill_process(prc[sel2].pid);//释放内存空间
prc[sel2].pid=-1;//改变标记
display_mem_usage();//显示
}
}
}
解释程序运行结果:
最初设置空闲分区的内存范围为0~1024
首先创建了大小为207的进程,剩余空间为817;
又创建了大小为239的进程单元,起始地址从207开始,剩余空间变为446;
接着释放了进程为3,4,5,6的进程单元数,于是空闲分区剩有了释放进程内存单元数的空间和起始地址为446,大小为89的空间。