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

  • 姓名:蒋浩天
  • 学号:201821121024
  • 班级:计算1811

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

创建结构体链表记录内存空间的使用情况,使用一个全局变量记录该链表的首指针。

//记录已使用内存空间 
typedef struct used_block{
    int pid;//进程id
    int size;//内存大小
    int start_addr;//首地址
    char process_name[PROCESS_NAME_LEN];//进程名
    struct allocated_block *next;
}UB;
//记录已使用内存空间链表首指针 
UB *used_block_head = NULL;

 

2. 记录空闲分区

同样创建结构体链表记录空闲内存空间的使用情况,使用一个全局变量记录该链表的首指针。

//记录空闲分区 
typedef struct free_block{
    int size;//大小 
    int start_addr;//起始地址 
    struct free_block_type *next;
}FB;

//记录空闲分区链表首指针 
FB *free_block;

 

3. 内存分配算法

使用最佳分配算法,每次分配都将最小块的满足需求空闲分区拿去分配。内存空间按空闲区从小到大排序。

 

分配内存,如果找到可满足空闲分区且分配后剩余空间足够大,则分割;如果找不可满足需要的空闲分区,但空闲分区之和能满足需要,则采用内存紧缩技术,进行空闲分区的合并,然后再分配;

int allocate_mem(UB *ab){
    /*分配内存模块*/
    FB *fbt,*pre;
    int request_size=ab->size;
    fbt = pre = free_block;

    //尝试寻找可分配空闲
    int f = find_free_mem(request_size);
    if(f == -1){
        //不够分配
        printf("Free mem is not enough,Allocate fail!\n");
        return -1;
    }else{
        if(f == 0){
            //需要内存紧缩才能分配
            memory_compact();
        }
        //执行分配
        do_allocate_mem(ab);
    }
    //重新排布空闲分区
    rearrange_BF();
    return 1;
} 

//执行分配内存
void do_allocate_mem(UB *ab){
    int request = ab->size;
    FB *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{
                    FB *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_BF(){//最佳适应算法,空闲分区按大小从小到大排序
    if(free_block == NULL || free_block->next == NULL)
        return;
    FB *t1,*t2,*head;
    head = free_block;
    for(t1 = head->next;t1;t1 = t1->next){
        for(t2 = head;t2 != t1;t2=t2->next){
            if(t2->size > t2->next->size){
                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 end_process(int p){
    UB *ab;
    printf("Kill Process,pid= %d\n",p);
    ab = find_process(p);
    if(ab!=NULL){
        free_mem(ab);    //释放该节点的分配空间
        dispose(ab);    //释放该数据结构节点
        return 0;
    }else{
        return -1;
    }
}

查找节点

//找到pid对应的链表节点
UB *find_process(int pid){
    UB *tmp = allocated_block_head;
    while(tmp != NULL){
        if(tmp->pid == pid){
            return tmp;
        }
        tmp = tmp->next;
    }
    printf("Cannot find pid:%d\n",pid);
    return NULL;
}

 

释放结构节点和结构空间

//释放链表节点
int dispose(UB *free_ab){
    /*释放ab数据结构节点*/
    UB *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(UB *ab){
    /* 将ab所表示的已分配区归还,并进行可能的合并 */
    int algorithm = ma_algorithm;
    FB *fbt,*pre,*work;
    fbt = (FB*)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;
}

 

5. 运行结果

根据实验要求,先初始化三个进程,进程所占空间随机生成,之后进入循环,结束释放一个进程,在分配生成一个所占空间大小随机的进程。

测试代码:

int main(int argc, char const *argv[]){
    free_block = init_free_block(mem_size); //初始化空闲区
    set_mem_size();
    int size;
    srand((unsigned)time(0));
    //初始化三个程序 
    for(int i=0;i<3;i++){
        
        size=rand()%100;
        create_process(size);
    }
    //测试12组数据 
    for(int j=0;j<12;j++){
        int p=j+1;
        end_process(p);//结束一个 
    
        size=rand()%100;
        create_process(size);//创造一个 
        display_mem_usage();
    } 
    
}

结果:

 

  

解释:根据之前初始化进程,空间中0到240被分配给进程1、2、3。第一次循环,进程1被释放,即空间0到84被释放。此时,空闲块为0-84和240-1000,较小块为0到84。创建的进程4,随机大小为27,小于84(先拿最小块比较),所以0到27被分配给进程4。所以第一次循环结束后得到图中结果。

 

 

 

 

解释:第二次循环,进程2被释放,即空间84到174被释放。此时空闲块为27-174和240-1000。生成进程5,随机大小为42,小于空闲块27-174的大小(先拿最小块比较),所以27-69被分配给进程5。此时空闲块为69-174和240-1000,结果如图。

 

 

解释:第三次循环,进程3被释放,即空间174到240被释放。此时空闲块为69-240和240-1000,相连合并。生成进程6,随机大小为96,所以69-165被分配给进程6。此时空闲块为165-1000,结果如图。

 

 

解释:第四次循环,进程4被释放,即空间0到27被释放。此时空闲块为0-27和165-1000。生成进程7,随机大小为63,因为空间0-27不够放(先拿最小块比较),空间165-1000够放,所以165-228被分配给进程7。此时空闲块为0-27和228-1000,结果如图。

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

posted @ 2020-05-16 22:06  HaotianJiang  阅读(333)  评论(0编辑  收藏  举报