实验内容
编写java程序,编程实现首次适应(First Fit,FF)、最佳适应(Best Fit,BF)动态分区分配及其回收算法。
要求:
1)说明两种算法的优点与缺陷;
2)设计多组数据,进行测试,输出分配与回收的执行过程数据,并适当分析为什么会得到这样的结果,是否符合预期。
基础知识简介
1、首次适应(First Fit)算法
该算法要求空闲分区以地址递增的次序排序。如果采用的是链表结构,分配时则从链表的开始顺序进行查找,直到找到一个能够满足进程大小要求的空闲分区为止。然后按进程的大小从分区中“切出”一块内存空间分配给请求者,余下的空闲分区仍然留在链表中。
该算法倾向于优先使用内存中低地址部分的空闲空间,高地址部分很少被利用,从而保证了高地址部分留有较大的空闲分区。其缺点是低地址部分不断被“切割”,致使留下许多难以利用的小空闲分区,而每次查找又都从低地址部分开始,这无疑会影响查找的速度。
2、最佳适应(Best Fit)算法
该算法的最佳的含义是指每次为进程分配内存时,总是把与进程大小最匹配的空闲分区分配出去该算法采用的数据结构若是空闲分区链,
首先要求将空闲分区按分区大小递增的顺序形成一空闲分区链。当进程要求分配内存时,第一次找到的满足要求的空闲区必然是最优的。该算法的优点是如果系统中有一空闲分区的大小正好与进程的大小相等,则必然选中该空闲块;另外,系统中可能保留有较大的空闲分区。
该算法的缺点是链表的头部会留下许多难以利用的小空闲区,称为碎片,从而影响分配的速度。
实验过程
首次适应算法:
- 优点:FF算法简单且高效,只需要遍历空闲分区链表找到第一个满足要求的分区即可完成分配。适用于快速找到可以容纳作业的分区,减少外部碎片的形成。
- 缺点:FF算法容易产生较大的外部碎片。当有多个较小的空闲分区时,FF算法可能会选择一个较大的空闲分区,导致剩余空间很小的碎片。
最佳适应(Best Fit,BF)算法:
- 优点:BF算法可以选择最合适大小的空闲分区,从而减少外部碎片的产生。它会遍历整个空闲分区链表,找到最小的能够满足作业需求的分区进行分配。
- 缺点:BF算法相对于FF算法来说更复杂,因为它需要遍历整个空闲分区链表来找到最佳的匹配。这可能会导致一定的性能损失。
代码
import java.util.LinkedList;
public 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;
}
}
//默认内存大小512K
public Memory(){
this.size = 80;
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));
}
//开始分配
private void doAllocation(int size, int location, Zone tmp) {
//要是剩的比最小分区MIN_SIZE小,则把剩下那点给前一个进程
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; public void fristFit(int size){
}
//如果回收的分区后一个是空闲就和后一个合并
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\t" + tmp.head + "\t\t\t" +
tmp.size + " \t\t\t" + tmp.isFree);
}
}
//遍历分区链表
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("无可用内存空间!");
}
public void bestFit(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));
}
}
}
测试类如下:
import java.util.ArrayList;
import java.util.List;
import java.util.Random;
import java.util.Scanner;
public class Main {
public static void main(String[] args) {
Memory my = new Memory();
Scanner sc = new Scanner(System.in);
List<Integer> list = new ArrayList<>();
Random random = new Random();
for (int i = 0;i < 5;i ++){
list.add(random.nextInt(20)) ;
}
System.out.println("首次适应法分配内存");
for (int size : list){
my.fristFit(size);
}
my.showZones();
boolean flag = true;
while (flag){
System.out.println("1 释放内存 2 退出释放内存的步骤");
int n = sc.nextInt();
switch (n){
case 1:{
System.out.println("输入想要释放内存的分区号");
int id = sc.nextInt();
my.collection(id);
my.showZones();
break;
}
case 2:{
flag = false;
break;
}
}
}
System.out.println("使用最佳适应法分配内存");
Memory my1 = new Memory();
for (int size : list){
my1.bestFit(size);
}
my1.showZones();
flag = true;
while (flag){
System.out.println("1 释放内存 2 退出释放内存的步骤");
int n = sc.nextInt();
switch (n){
case 1:{
System.out.println("输入想要释放内存的分区号");
int id = sc.nextInt();
my.collection(id);
my.showZones();
break;
}
case 2:{
flag = false;
break;
}
}
}
}
}