操作系统实验—动态分区分配算法

提示:文章写完后,目录可以自动生成,如何生成可参考右边的帮助文档


前言

所有类都在一个包(os.test2)里,步骤4里的函数都封装在Distribute类里。

一、实验原理

       动态分区分配是根据进程的实际需要,动态地为作业从可用内存中划分出一个分区,刚好能满足作业的实际需要。而在分配时,须按照一定的分配算法,从空闲分区表或空闲分区链中选出一分区分配给该作业。

在本实验中运用了四种分配算法,分别是首次适应算法循环首次适应算法最坏适应算法最佳适应算法

实验要求:

二、实验步骤

1.创建PCB类和MemoryBlock类

代码如下:

PCB:进程

package os.test2;

public class PCB {
    String name;      //进程名
    int size;        //进程大小
    int sadd;      //进程分配起始地址
    int areaId;    //进程分配所在内存块区号
    public PCB(String name,int size){
        this.name=name;
        this.size=size;
        sadd=-1;           //-1表示未分配
        areaId=-1;         //-1表示未分配
    }
}

 MemoryBlock:进程块

package os.test2;

public class MemoryBlock {
    int size;   //大小
    int sadd;   //起始地址
    int area_code;   //区号
    public MemoryBlock(int size,int sadd,int area_code){
        this.size=size;
        this.sadd=sadd;
        this.area_code=area_code;
    }
}

2.创建FreeTable类

空闲分区表

代码如下:

package os.test2;

import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;

public class FreeTable {
        List<MemoryBlock> freeTable =new ArrayList();    //初始化的空闲分区表
        public boolean check(int size,int sadd){         //检测是否可以添加大小为size,起始地址为sadd的内存块
            if(freeTable.isEmpty())                     //情况1:空闲分区表中无内存块
                return true;
            for(MemoryBlock cur:freeTable){            //情况2:空闲分区表中有内存块
                if(sadd==cur.sadd)                      //情况2.1:空闲分区表中有输入的内存块起始地址与某个内存块重复
                    return false;
                if(sadd<cur.sadd){                      
                    if(sadd+size<=cur.sadd);
                    else
                        return false;                  //情况2.2:空闲分区表中有输入内存块与某个高地址内存块空间重合
                }
                else{
                    if(sadd>=cur.sadd+cur.size);       //情况2.2:空闲分区表中有输入内存块与某个低地址内存块空间重合
                        return false;
                }
            }
            return true;
        }
        public void addMeb() {                       //初始化添加内存块
            Scanner sc = new Scanner(System.in);
            do {
                System.out.println("请输入大小、始址:");
                int size = sc.nextInt();
                while(size<=0) {
                    System.out.println("大小不合法,请重新输入!");
                    size = sc.nextInt();
                }
                int sadd = sc.nextInt();
                while(sadd<0) {
                    System.out.println("地址不合法,请重新输入!");
                    sadd= sc.nextInt();
                }
                if (check(size,sadd)) {                          //check()函数检测为true才进空闲分区表
                    MemoryBlock cur=new MemoryBlock(size,sadd,freeTable.size());
                    freeTable.add(cur);
                    System.out.println("内存块添加成功!是否继续添加:1:是   2:否  ");
                    int flag=sc.nextInt();
                    if(flag==1);
                    else
                        break;
                }
            }while(true);
        }
        public void findMebTable(List<MemoryBlock>MBList){     //查看分区表
            if(MBList.isEmpty())
                System.out.println("当前无内存块!");
            for(MemoryBlock cur:MBList)
                System.out.println("区号:"+cur.area_code+"  大小:"+cur.size+"  起始地址:"+cur.sadd);
        }
}

3.设计主窗口类

主要实现初始化空闲分区表和进程添加的界面。

代码如下:

package os.test2;

import java.util.*;

public class Psch {
    static FreeTable ft=new FreeTable();        //初始化空闲分区表
    static List<PCB>pcbList=new ArrayList<>();   //初始化进程序列
    static HashSet<String>set=new HashSet<>();   //set添加进程名防止重复添加

    //添加进程
    public static void addPCB(){
        Scanner sc=new Scanner(System.in);
        int count=1;
        do {
            System.out.println("请输入进程名:");
            String name = sc.next();
            while (set.contains(name)) {
                System.out.println("已有此进程,请重新输入进程名:");
                name = sc.next();
            }
            set.add(name);
            System.out.println("请输入进程大小:");
            int size = sc.nextInt();
            pcbList.add(new PCB(name, size));
            System.out.println("是否继续添加:1:是  2:否");
            count=sc.nextInt();
        }while(count==1);
    }

    //打印进程表
    public static void findPCBS(List<PCB> pcbs){
        for(PCB pcb:pcbs){
            System.out.print("进程名:"+pcb.name+"  进程大小:"+pcb.size);
            if(pcb.sadd==-1)
                System.out.println("  未分配内存");
            else{
                System.out.print("  已分配内存");
                System.out.println("  起始地址:"+pcb.sadd+"  分配内存区号:"+pcb.areaId);
            }
        }
    }

    //初始化界面函数
    public static void MainMenu() {
        Scanner sc=new Scanner(System.in);
        int count1 = 1;
        System.out.println("初始化内存块:");
        while (count1 == 1) {
            System.out.println("**************************");
            System.out.println("请输入你需要的服务:");
            System.out.println("1.添加空闲内存块");
            System.out.println("2.查看空闲分区表");
            System.out.println("3.内存分配");
            System.out.println("0.退出");
            int num = sc.nextInt();
            switch (num) {
                case 1:
                    ft.addMeb();
                    break;
                case 2:
                    ft.findMebTable(ft.freeTable);
                    break;
                case 3:
                    distribute();
                    break;
                case 0:
                    count1 = 0;
                    break;
                default:
                    System.out.println("输入非法,请输入其他选项!");
                    break;
            }
        }
    }

    //分配界面函数
    public static void distribute() {
        Distribute dis = new Distribute();
        Scanner sc = new Scanner(System.in);
        int count=1;
        while (count == 1) {
            System.out.println("**************************");
            System.out.println("请输入你需要的服务:");
            System.out.println("1.添加进程");
            System.out.println("2.查看进程");
            System.out.println("3.进程分配");
            System.out.println("0.退出");
            int num = sc.nextInt();
            switch (num) {
                case 1:
                    addPCB();
                    break;
                case 2:
                    findPCBS(pcbList);
                    break;
                case 3:
                    dis.disMB();
                    break;
                case 0:
                    count=0;
                    break;
                default:
                    System.out.println("输入非法,请输入其他选项!");
                    break;
            }
        }
    }
    public static void main (String[]args){
        MainMenu();
    }
}

4.进程分配与回收类(Distribute类)

主要实现四种分配算法,分别是首次适应算法循环首次适应算法最坏适应算法最佳适应算法以及分配后的回收算法

1.分配进程界面函数

代码如下:

 public void disMB() {            //为进程分配空间,算法选择界面
        Scanner sc = new Scanner(System.in);
        int count = 1;
        while (count == 1) {
            List<MemoryBlock> useMB = new ArrayList<>();
            for (MemoryBlock cur : ft.freeTable)
                useMB.add(new MemoryBlock(cur.size, cur.sadd,cur.area_code));   //复制内存块用例
            List<PCB> usePCB = new ArrayList<>();
            for (PCB cur : pcbList)
                usePCB.add(new PCB(cur.name, cur.size));                  //复制进程用例
            System.out.println("**************************");
            System.out.println("请选择进程分配算法:");
            System.out.println("1.最佳适应算法");
            System.out.println("2.最坏适应算法");
            System.out.println("3.首次适应算法");
            System.out.println("4.循环首次适应算法");
            System.out.println("0.退出");
            System.out.println("**************************");
            int num = sc.nextInt();
            switch (num) {
                case 1 -> this.BF(usePCB, useMB);
                case 2 -> this.WF(usePCB, useMB);
                case 3 -> this.FF(usePCB, useMB);
                case 4 -> this.NF(usePCB, useMB);
                case 0 -> count = 0;
                default -> System.out.println("输入非法,请输入其他选项!");
            }
        }
    }

2.最佳适应算法(BF)

代码如下:

//最佳适应算法
    public void BF(List<PCB>usePCB,List<MemoryBlock>useMB) {
        useMB.sort(Comparator.comparingInt(x -> x.size));   //内存块以大小升序排列
        for (PCB pcb : usePCB) {
            for(MemoryBlock cur:useMB){
                if(useMB.isEmpty())
                    break;
                if(pcb.size>cur.size);
                //内存块符合分配的两种情况:内存完全分配出去和部分分配出去
                else{
                    int index=useMB.indexOf(cur);
                    if(cur.size==pcb.size){                    //内存块完全分配出去
                        pcb.areaId=cur.area_code;
                        pcb.sadd=cur.sadd;
                        useMB.remove(index);
                        break;
                    }
                    pcb.areaId=cur.area_code;              //内存块部分分配出去了->剩余所有空闲内存块重新排序
                    pcb.sadd=cur.sadd;
                    cur.sadd+= pcb.size;
                    cur.size-= pcb.size;
                    useMB.sort(Comparator.comparingInt(x -> x.size));
                    break;
                }
            }
        }
        this.dised(usePCB,useMB);
    }

3.最坏适应算法(WF)

代码如下:

 //最坏适应算法
    public void WF(List<PCB>usePCB,List<MemoryBlock>useMB){
        useMB.sort((x1,x2)-> x2.size-x1.size);         //内存块以大小降序排列
        for (PCB pcb : usePCB) {
            if(useMB.isEmpty())
                break;
            MemoryBlock cur=useMB.get(0);         //只需看最大的进程是否满足
            if(pcb.size<=cur.size){              //满足:内存块符合分配的两种情况:内存完全分配出去和部分分配出去
                int index=useMB.indexOf(cur);
                if(cur.size==pcb.size){         //内存块完全分配出去
                    pcb.areaId=cur.area_code;
                    pcb.sadd=cur.sadd;
                    useMB.remove(index);
                    continue;
                }
                pcb.areaId=cur.area_code; //内存块部分分配出去了->剩余所有空闲内存块重新排序
                pcb.sadd=cur.sadd;
                cur.sadd+= pcb.size;
                cur.size-= pcb.size;
                useMB.sort((x1, x2) -> x2.size - x1.size);
            }
        }
        this.dised(usePCB,useMB);
    }

4.首次适应算法(FF)

代码如下:

//首次适应算法
    public void FF(List<PCB>usePCB,List<MemoryBlock>useMB){
        useMB.sort(Comparator.comparingInt(x -> x.sadd));
        for (PCB pcb : usePCB) {
            for(MemoryBlock cur:useMB){
                if(useMB.isEmpty())
                    break;
                if(pcb.size>cur.size) ;
                else{                                   //内存块符合分配的两种情况:内存完全分配出去和部分分配出去
                    int index=useMB.indexOf(cur);
                    if(cur.size==pcb.size){             //内存块完全分配出去
                        pcb.areaId=cur.area_code;
                        pcb.sadd=cur.sadd;
                        useMB.remove(index);
                        break;
                    }
                    pcb.areaId=cur.area_code;            //内存块部分分配出去了->剩余所有空闲内存块重新排序
                    pcb.sadd=cur.sadd;
                    cur.sadd+= pcb.size;
                    cur.size-= pcb.size;
                    break;
                }
            }
        }
        this.dised(usePCB,useMB);

    }

5.循环首次适应算法(NF)

代码如下:

//循环首次适应算法
    public void NF(List<PCB>usePCB,List<MemoryBlock>useMB) {
        useMB.sort(Comparator.comparingInt(x -> x.sadd));
        MemoryBlock cur = useMB.get(0);
        for (PCB pcb : usePCB) {
            if (useMB.isEmpty())
                break;
            int curIndex = useMB.indexOf(cur);
            while (pcb.size > cur.size) {            //cur不满足
                int index = useMB.indexOf(cur);
                if (useMB.size() > index + 1)             //分区表后面还有内存块
                    cur = useMB.get(index + 1);
                else                                    //  分区表后面没有内存块,即cur为空闲分区表最后一个,则从头开始再去适配
                    cur = useMB.get(0);
                if (index == curIndex)                //已经找了一圈(全部的空闲内存块)还是没有符合的
                    break;
            }
            if (pcb.size > cur.size) ;           //即上面index==curIndex(已经找了一圈还是没有符合的)这种情况,放弃为pcb分配内存空间
            else {                                //满足:内存块符合分配的两种情况:内存完全分配出去和部分分配出去
                int index = useMB.indexOf(cur);
                if (cur.size == pcb.size) {       //内存块完全分配出去
                    pcb.areaId=cur.area_code;
                    pcb.sadd=cur.sadd;
                    useMB.remove(index);
                    cur=useMB.size() > index ?useMB.get(index):useMB.get(0);  //cur指向进程表的下一个(无下一个就是指向开头)
                    continue;
                }
                pcb.areaId=cur.area_code;
                pcb.sadd=cur.sadd;
                cur.sadd += pcb.size;
                cur.size -= pcb.size;
            }
        }
        this.dised(usePCB, useMB);
    }

6.分配后功能界面

每次调用分配算法之后,可以查看进程分配情况和空闲分区表使用情况,也可以选择回收进程。

代码如下:

//分配后功能界面
    public void dised(List<PCB> usePCB, List<MemoryBlock> useMB) {    //已经分配成功,输出或者回收
        Scanner sc = new Scanner(System.in);
        int count2 = 1;
        do {
            System.out.println("**************************");
            System.out.println("请输入你需要的服务:");
            System.out.println("1.查看进程分配情况");
            System.out.println("2.查看空闲分区表");
            System.out.println("3.内存回收");
            System.out.println("0.退出");
            int num = sc.nextInt();
            switch (num) {
                case 1 -> findPCBS(usePCB);
                case 2 -> ft.findMebTable(useMB);
                case 3 -> this.retrieve(usePCB, useMB);
                case 0 -> count2 = 0;
                default -> System.out.println("输入非法,请输入其他选项!");
            }
        } while (count2 == 1);
    }

7.回收进程算法

代码如下:

 //回收算法
    public void retrieve(List<PCB> usePCB, List<MemoryBlock> useMB) {   //回收函数
        HashMap<String, PCB> pcbMap = new HashMap<>();      //已经分配成功的进程,建立进程名与进程的关系
        Scanner sc = new Scanner(System.in);
        for (PCB pcb : usePCB) {
            if (pcb.sadd == -1) ;
            else
                pcbMap.put(pcb.name, pcb);
        }
        int flag = 1;
        while (flag == 1) {
            if (pcbMap.isEmpty()) {  //basecase
                System.out.println("无可回收进程!");
                break;
            }
            System.out.println("已分配内存进程如下:");
            for (PCB pcb : pcbMap.values())
                System.out.println("进程名:" + pcb.name + "  进程大小:" + pcb.size + "  起始地址:" + pcb.sadd+"  所在区号:"+pcb.areaId);
            System.out.println("请选择要回收的进程:");
            String name = sc.next();
            while (!pcbMap.containsKey(name)) {
                System.out.println("此进程名输入无效,请重新输入!");
                name = sc.next();
            }
            PCB rem = pcbMap.remove(name);
            MemoryBlock curt=null;
            for (MemoryBlock cur : useMB) {      //3种情况
                curt=cur;
                if (rem.areaId != cur.area_code);
                else {
                    if(cur.sadd== rem.sadd+rem.size){
                        cur.sadd = rem.sadd;
                        cur.size += rem.size;
                        rem.sadd = -1;
                        return;
                    }else{
                        MemoryBlock mb=new MemoryBlock(rem.size, rem.sadd,rem.areaId);
                        useMB.add(mb);
                        rem.sadd=-1;
                        rem.areaId=-1;
                        return;
                    }
                }
            }
            if (rem.areaId != curt.area_code){
                MemoryBlock mb=new MemoryBlock(rem.size, rem.sadd,rem.areaId);
                useMB.add(mb);
                rem.sadd=-1;
                rem.areaId=-1;
            }
            System.out.println("是否继续回收:1:是  2:否");
            flag = sc.nextInt() == 1 ? 1 : 2;   //非1都可退出
        }
    }

总结

回收算法还有些瑕疵,以后再改。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值