实验三 动态分区算法
前言
参考教材《操作系统 第四版》汤小丹
首次适应算法(First Fit)。空闲分区以地址递增的次序连接。分配内存时顺序查找,找到大小能满足要求的第一个空闲分区
邻近适应算法(Next Fit)。又称循环首次适应算法,由首次适应算法演变而成。不同之处是,分配内存时从上次查找结束的位置开始继续查找
最佳适应算法(Best Fit)。空闲分区按容量递增的方式形成分区链,找到第一个满足要求的空闲分区
最坏适应算法(Worst Fit)。又称最大适应算法,空闲分区以容量递减的次序链接,找到第一个能满足要求的空闲分区,即挑选出最大的分区
实验三Memory类中建了很多内部内和方法,分开展示代码部分只是为了方便学习每段代码的具体逻辑。运行代码直接C2C完整代码即可,以防某个函数或类放错位置
实验目的
通过这次实验,加深对动态分区分配算法的理解,进一步掌握首次适应算法、循环首次适应算法、最佳适应算法、最坏适应算法的实现方法
实验内容
设计程序模拟四种动态分区分配算法:首次适应算法、循环首次适应算法、最佳适应算法和最坏适应算法的工作过程。分别利用四种动态分区分配算法将m个进程放入空闲分区,给出进程在空闲分区中的分配情况
实验步骤
内存分配菜单
public void allocation(int size) { System.out.println("1.首次适应算法 2.循环首次适应算法 3.最佳适应算法 4.最坏适应算法"); System.out.print("请选择分配算法:"); Scanner in = new Scanner(System.in); int choice = in.nextInt(); switch (choice) { case 1: FF(size); break; case 2: NF(size); break; case 3: BF(size); break; case 4: WF(size); break; default: System.out.println("请重新选择!"); } }
|
首次适应算法
private void FF(int size) { for (pointer = 0; pointer < zones.size(); pointer++) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { doAllocation(size, pointer, tmp); return; } } System.out.println("无可用内存空间!"); }
|
循环首次适应算法
private void NF(int size) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { doAllocation(size, pointer, tmp); return; } int len = zones.size(); int i = (pointer + 1) % len; for (; i != pointer; i = (i + 1) % len) { tmp = zones.get(i); if (tmp.isFree && (tmp.size > size)) { doAllocation(size, i, tmp); return; } } System.out.println("无可用内存空间!"); }
|
最佳适应算法
private void BF(int size) { int flag = -1; int min = this.size; for (pointer = 0; pointer < zones.size(); pointer++) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { if (min > tmp.size - size) { min = tmp.size - size; flag = pointer; } } } if (flag == -1) { System.out.println("无可用内存空间!"); } else { doAllocation(size, flag, zones.get(flag)); } }
|
最坏适应算法
private void WF(int size) { int flag = -1; int max = 0; for (pointer = 0; pointer < zones.size(); pointer++) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { if (max < tmp.size - size) { max = tmp.size - size; flag = pointer; } } } if (flag == -1) { System.out.println("无可用内存空间!"); } else { doAllocation(size, flag, zones.get(flag)); } }
|
内存分配
private void doAllocation(int size, int location, Zone tmp) { if (tmp.size - size <= MIN_SIZE) { tmp.isFree = false; } else { Zone split = new Zone(tmp.head + size, tmp.size - size); zones.add(location + 1, split); tmp.size = size; tmp.isFree = false; } System.out.println("成功分配 " + size + "KB 内存!"); }
|
内存回收
public void collection(int id) { if (id >= zones.size()) { System.out.println("无此分区编号!"); return; } Zone tmp = zones.get(id); int size = tmp.size; if (tmp.isFree) { System.out.println("指定分区未被分配, 无需回收"); return; } if (id < zones.size() - 1 && zones.get(id + 1).isFree) { Zone next = zones.get(id + 1); tmp.size += next.size; zones.remove(next); } if (id > 0 && zones.get(id - 1).isFree) { Zone previous = zones.get(id - 1); previous.size += tmp.size; zones.remove(id); id--; } zones.get(id).isFree = true; System.out.println("内存回收成功!, 本次回收了 " + size + "KB 空间!"); }
|
展示分区
// 展示分区状况 public void showZones() { System.out.println("分区编号\t 分区始址\t 分区大小\t 空闲状态\t"); for (int i = 0; i < zones.size(); i++) { Zone tmp = zones.get(i); System.out.println(i + "\t\t" + tmp.head + "\t\t" + tmp.size + " \t" + tmp.isFree); } }
|
主函数
public class 动态分区算法 { public static void main(String[] args) { Memory my = new Memory(); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入要分配内存还是要释放内存"); System.out.println("1.分配内存 2.释放内存 3.展示分区状况"); int n = sc.nextInt(); switch (n) { case 1: { System.out.println("请输入要分配的内存大小"); int size = sc.nextInt(); my.allocation(size); my.showZones(); break; } case 2: { System.out.println("输入想要释放内存的分区号"); int id = sc.nextInt(); my.collection(id); break; } case 3: { my.showZones(); break; } default: System.out.println("输的不对"); } } } }
|
完整代码
package 操作系统实验;
import java.util.Arrays; import java.util.Scanner; import java.util.LinkedList;
public class 动态分区算法 { public static void main(String[] args) { Memory my = new Memory(); Scanner sc = new Scanner(System.in); while (true) { System.out.println("请输入要分配内存还是要释放内存"); System.out.println("1.分配内存 2.释放内存 3.展示分区状况"); int n = sc.nextInt(); switch (n) { case 1: { System.out.println("请输入要分配的内存大小"); int size = sc.nextInt(); my.allocation(size); my.showZones(); break; } case 2: { System.out.println("输入想要释放内存的分区号"); int id = sc.nextInt(); my.collection(id); break; } case 3: { my.showZones(); break; } default: System.out.println("输的不对"); } } } }
class Memory { private int size; private static final int MIN_SIZE = 2; private LinkedList<Zone> zones; private int pointer;
class Zone { private int size; private int head; private boolean isFree;
public Zone(int head, int size) { this.head = head; this.size = size; this.isFree = true; } }
public Memory() { this.size = 512; this.pointer = 0; this.zones = new LinkedList<>(); zones.add(new Zone(0, size)); }
public Memory(int size) { this.size = size; this.pointer = 0; this.zones = new LinkedList<>(); zones.add(new Zone(0, size)); }
public void allocation(int size) { System.out.println("1.首次适应算法 2.循环首次适应算法 3.最佳适应算法 4.最坏适应算法"); System.out.print("请选择分配算法:"); Scanner in = new Scanner(System.in); int choice = in.nextInt(); switch (choice) { case 1: FF(size); break; case 2: NF(size); break; case 3: BF(size); break; case 4: WF(size); break; default: System.out.println("请重新选择!"); } }
private void FF(int size) { for (pointer = 0; pointer < zones.size(); pointer++) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { doAllocation(size, pointer, tmp); return; } } System.out.println("无可用内存空间!"); }
private void NF(int size) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { doAllocation(size, pointer, tmp); return; } int len = zones.size(); int i = (pointer + 1) % len; for (; i != pointer; i = (i + 1) % len) { tmp = zones.get(i); if (tmp.isFree && (tmp.size > size)) { doAllocation(size, i, tmp); return; } } System.out.println("无可用内存空间!"); }
private void BF(int size) { int flag = -1; int min = this.size; for (pointer = 0; pointer < zones.size(); pointer++) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { if (min > tmp.size - size) { min = tmp.size - size; flag = pointer; } } } if (flag == -1) { System.out.println("无可用内存空间!"); } else { doAllocation(size, flag, zones.get(flag)); } }
private void WF(int size) { int flag = -1; int max = 0; for (pointer = 0; pointer < zones.size(); pointer++) { Zone tmp = zones.get(pointer); if (tmp.isFree && (tmp.size > size)) { if (max < tmp.size - size) { max = tmp.size - size; flag = pointer; } } } if (flag == -1) { System.out.println("无可用内存空间!"); } else { doAllocation(size, flag, zones.get(flag)); } }
private void doAllocation(int size, int location, Zone tmp) { if (tmp.size - size <= MIN_SIZE) { tmp.isFree = false; } else { Zone split = new Zone(tmp.head + size, tmp.size - size); zones.add(location + 1, split); tmp.size = size; tmp.isFree = false; } System.out.println("成功分配 " + size + "KB 内存!"); }
public void collection(int id) { if (id >= zones.size()) { System.out.println("无此分区编号!"); return; } Zone tmp = zones.get(id); int size = tmp.size; if (tmp.isFree) { System.out.println("指定分区未被分配, 无需回收"); return; } if (id < zones.size() - 1 && zones.get(id + 1).isFree) { Zone next = zones.get(id + 1); tmp.size += next.size; zones.remove(next); } if (id > 0 && zones.get(id - 1).isFree) { Zone previous = zones.get(id - 1); previous.size += tmp.size; zones.remove(id); id--; } zones.get(id).isFree = true; System.out.println("内存回收成功!, 本次回收了 " + size + "KB 空间!"); }
public void showZones() {
System.out.println("分区编号\t 分区始址\t 分区大小\t 空闲状态\t"); for (int i = 0; i < zones.size(); i++) { Zone tmp = zones.get(i); System.out.println(i + "\t\t" + tmp.head + "\t\t" + tmp.size + " \t" + tmp.isFree); }
} }
|
运行结果
首先分配一些内存(手动先输好),然后展示四个算法的运行结果。如图

使用首次适应算法,申请内存大小10kb,遍历空闲分区找到第二个分区为空,所以插入分区2,剩下40kb作为分区3

使用循环首次适应算法,申请内存大小10kb,上一次运行位置在2号分区,所以从2号分区开始寻找,3号分区为空,将10kb放入三号分区,剩下30kb作为分区4

使用最佳适应算法算法,申请内存大小3kb。首先从小到大遍历空闲分区,7号分区大小15kb,满足条件。将3kb插入7号分区,剩余10kb作为8号分区

使用最坏适应算法,申请内存大小2kb。首先从大到小遍历分区,14号分区最大,所以将2kb插入14号分区,剩余232kb作为15号分区

释放11号分区,将10、11、12号分区合并为10号分区

总结
首次适应算法,从链首开始,查找可以用的空闲区,保留了高地址部分的大空闲区,缺点,低地址部分不断被划分,留下许多小的、很难利用的空闲区
循环首次适应算法,不是每次都从首地址查找,而是从上次查找结束的地方开始找,使空闲区分布的更加均匀,减少查询的开销,缺乏大的空闲区
最佳适应算法,每次查找时,将刚刚好的、稍微大一点点的空闲区分给作业,避免了“大材小用”,但留下许多难以利用的小空闲区
最差适应算法,与“最佳”相反,每次都将最大的空闲区分配给作业,产生碎片的可能性小,对中小型作业有利
附一张《王道考研-操作系统》第37讲动态分区总结
