操作系统第5次实验报告:内存管理

  • 姓名毛琳淇
  • 学号201821121007
  • 班级计算1811

1. 记录内存空间使用情况

/*每个进程分配到的内存块描述*/

typedef struct allocated_block{

    int pid;

    int size;

    int start_addr;

    char process_name[NAME_LEN];

    struct allocated_block *next;

}AB;

/*进程分配内存块链表的首指针*/

AB *allocated_block_head = NULL;

定义已分配分区的结构体Allocated_block,定义一个指针Allocated_block_head指向链表表头,为进程分配内存空间时,就将分配到内存空间的进程块节点添加到链表中。

2. 记录空闲分区

/*描述每一个空闲块的数据结构*/

typedef struct Free_block_type{

    int size;

    int start_addr;

    struct Free_block_type *next;

}FBT;

/*指向内存中空闲块链表的首指针*/

FBT *free_block;

空闲分区的结构体Free_block_type,定义一个指针free block指向链表表头,对内存初始化后,空闲分区按从小到大进行排序,自表头开始查找到第一个满足要求的自由分区分配。

3. 内存分配算法

采用的是最先适应法:

按分区的起始地址的递增次序,从头查找,找到符合要求的第一个分区。

尽可能的利用了低地址空间,从而保证高地址有较大的空闲区来防止要求内存较多的进程或作业

该算法的分配和释放的时间性能较好

int Allocate_mem(AB *ab){  /*分配内存模块*/

    FBT *fbt,*pre;

    int request_size=ab->size;

    fbt = pre = free_block;

    //寻找可分配空闲空间

    int f = find_free_mem(request_size);

    if(f == -1){

        //不够分配

        printf("空闲内存不足,内存分配失败!\n");

        return -1;

    }else{

        if(f == 0){

            //需要内存紧缩才能分配

            memory_compact();

        }

        //执行分配

        do_allocate_mem(ab);

    }

    //重新排布空闲分区

    rearrange(ma_algorithm);

    return 1;

}

 

//执行分配内存

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;

            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(int pid){

    AB *ab;

    ab = find_process(pid);

    if(ab!=NULL){

        free_mem(ab);    //释放ab所表示的分配表

        dispose(ab);    //释放ab数据结构节点

        return 0;

    }else{

        return -1;

    }

}

5. 运行结果

1)产生测试数据

随机为3个进程分配、释放内存10次以上,即随机产生10组以上数据:(进程Pi 分配内存大小) 或者 (进程Pi结束)

代码:

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();//显示

        }

    }

}

 

 

运行结果:

 

 

 

 

 

 

 

(2)解释结果

初始内存:1024

 

 

第一次操作为进程process-02分配了从地址0开始,大小为44的一块内存单元,分配后空闲分区内存剩余地址从地址44开始,大小为980的一块区域。

 

 

 第二次操作为进程process-03分配了地址44开始,大小为33的一块内存单元,分配后空闲分区内存剩余地址从地址77开始,大小为947的一块区域。

 

 

 第三次操作为进程process-01分配了从地址77开始大小为37的一块内存单元,分配后空闲分区内存剩余地址从114开始,大小为910的一块区域。

 

 

 第四次操作释放了进程process-01的内存空间,释放后空闲分区内存剩余地址从77开始,大小为947的一块区域。

posted @ 2020-05-16 17:21  my7in7i  阅读(283)  评论(0编辑  收藏  举报