• 操作系统第五次实验:内存管理


    0.个人信息:

    姓名:张越

    学号:201821121006

    班级:计算1811

    1.记录内存使用状况:

    //每个进程分配到的内存块的描述
    struct allocated_block
    {
        int pid;
        int size;         //进程大小
        int start_addr;   //进程分配到的内存块的起始地址
        char process_name[PROCESS_NAME_LEN];  //进程名
        struct allocated_block *next;   //指向下一个进程控制块
    };
    

     首先我们需要进行上述链表allocated_block进行定义,其中具体描述包括:pid(进程id),size(进程大小),start_addr(开始地址),pro_name[](进程名数组),next(next指针)。还需要一个这个链表计算机的内存块信息,头指针初始值设置为空,一旦进行内存分配了,头指针进行向下移动。

    2.记录空闲分区

    //描述每一个空闲块的数据结构
    struct free_block_type
    {
        int size;        //空闲块大小
        int start_addr;  //空闲块起始位置
        struct free_block_type *next;  //指向下一个空闲块
    };
    

    还是用链表来记录空闲分区,首先定义一个结构体free_block_type来存放空闲内存块,接着定义一个全局指针变量free_block来指向链表的头结点。当内存空间进行了初始化之后,所有的内存分区都是空闲分区。

    3. 内存分配算法

    首次适应算法:

    //按照首次适应算法给新进程分配内存空间
    int allocate_FF(struct allocated_block *ab)
    {
        int ret;
        struct free_block_type *pre= NULL,*ff= free_block;
        if(ff== NULL)
            return -1;
        while(ff!= NULL)
        {
            if(ff->size>= ab->size)
            {
                ret= allocate(pre,ff,ab);
                break;
            }
            pre= ff;
            pre= pre->next;
        }
        if(ff== NULL&&current_free_mem_size> ab->size)
            ret= mem_retrench(ab);
        else
            ret= -2;
        rearrange_FF();
        return ret;
    }
    

      原理:该算法从空闲分区链首开始查找,直至找到一个能满足其大小要求的空闲分区为止。然后再按照作业的大小,从该分区中划出一块内存分配给请求者,余下的空闲分区仍留在空闲分区链 中。

         特点: 该算法倾向于使用内存中低地址部分的空闲区,在高地址部分的空闲区很少被利用,从而保留了高地址部分的大空闲区。显然为以后到达的大作业分配大的内存空间创造了条件。

    4.内存释放算法

    //释放ab数据结构结点
    int dispose(struct allocated_block *free_ab)
    {
        struct allocated_block *pre,*ab;
        if(free_block== NULL)
            return -1;
        if(free_ab== allocated_block_head)   //如果要释放第一个结点
        {
            allocated_block_head= allocated_block_head->next;
            free(free_ab);
        }
        else
        {
            pre= allocated_block_head;
            ab= allocated_block_head->next; 
            //找到free_ab
            while(ab!= free_ab)
            {
                pre= ab;
                ab= ab->next;
            }
            pre->next= ab->next;
            free(ab);
        }
        return 1;
    }
    
    //将ab所表示的已分配区归还,并进行可能的合并
    int free_mem(struct allocated_block *ab)
    {
        int algorithm= ma_algorithm;
        struct free_block_type *fbt,*pre,*work;
        fbt= (struct free_block_type*)malloc(sizeof(struct free_block_type));
        if(!fbt)
            return -1;
        pre= free_block;
        fbt->start_addr= ab->start_addr;
        fbt->size= ab->size;
        fbt->next= NULL;
        if(pre!= NULL)
        {
            while(pre->next!= NULL)
                pre= pre->next;
            pre->next= fbt;
        }
        else
        {
            free_block= fbt;
        }
        rearrange_FF();
        pre= free_block;
        work= pre->next;
        while(work!= NULL)
        {
            if(pre->start_addr+ pre->size== work->start_addr)
            {
                pre->size+= work->size;
                free(work);
                work= pre->next;
            }
            else
            {
                pre= work;
                work= work->next;
            }
        }
        current_free_mem_size+= ab->size;
        return 1;
    }
    
    //删除进程,归还分配的存储空间,并删除描述该进程内存分配的结点
    void kill_process()
    {
        struct allocated_block *ab;
        int pid;
        printf("Kill Process,pid=");
        scanf("%d",&pid);
        getchar();
        ab= find_process(pid);
        if(ab!= NULL)
        {
            free_mem(ab);  //释放ab所表示的分配区
            dispose(ab);   //释放ab数据结构结点
        }
    }
    

      关于内存释放分为三个步骤:首先是释放ab结点,接着将ab所表示的已分配区归还,并进行可能的合并,最后删除进程,归还分配的存储空间,并删除描述该进程内存分配的结点。

    5.运行结果:

    测试代码:
    int main(int argc, char const *argv[]){ int p1,p2; 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){ p1=rand()%2; int count=0; for(int j=0;j<PROCESS_NUM;++j){ if(prc[j].pid!=-1) count++; } if((count==PROCESS_NUM && p1==0)||total==10){ p1=1; } if(count==0 && p1==1){ p1=0; } if(p1==0){ do{ p2=rand()%PROCESS_NUM; }while(prc[p2].pid!=-1); alloc_process(prc[p2]); prc[p2].pid=pid; total++; display_mem_usage();//输出内存使用情况 } else { do{ p2=rand()%PROCESS_NUM; }while(prc[p2].pid==-1); kill_process(prc[p2].pid); prc[p2].pid=-1; display_mem_usage(); } } }

     

    下面对前4组数据进行具体的内容分析:

    说明:我设置的初始空闲分区的内存范围为0-1024。

    1.为进程process_01分配了起始地址为0,大小为13的内存空间,分配结束后空闲分区的剩余存储地址从13开始,大小为1011的空间。

    2.为进程process_02分配了起始地址为13,大小为14的内存空间,分配结束后空闲分区的剩余存储地址从27开始,大小为997的空间。

    3.为进程process_03分配了起始地址为27,大小为24的存储空间,分配结束后空闲分区的剩余存储地址从51开始,大小为973的空间。

    3.为进程process_04分配了起始地址为51,大小为57的存储空间,分配结束后空闲分区的剩余存储地址从51开始,大小为916的空间

    参考链接:

    https://www.cnblogs.com/XNQC1314/p/9065236.html

    https://blog.csdn.net/weixin_39282491/article/details/81045441

  • 相关阅读:
    使用kbmmw 生成REST 服务OpenAPI函数原型
    kbmmw 5.08 正式发布
    在datasnap 中使用unidac 访问数据(客户端)
    使用双引擎,让kbmmw 的客户端访问更方便
    使用kbmMWConfiguration 让 kbmmw smartservice 更聪明
    CE lua脚本
    error LNK2019: 无法解析的外部符号 __vsnwprintf,该符号在函数 "long __stdcall StringVPrintfWorkerW
    安装 directx sdk 出现 S1023 解决
    dx11的一些数据结构
    git 比较 change to be committed
  • 原文地址:https://www.cnblogs.com/hltz/p/12900325.html
Copyright © 2020-2023  润新知