实验内容
主存储器空间的分配和回收。
实验目的
一个好的计算机系统不仅要有一个足够容量的、存取速度高的、稳定可靠的主存储器,而且要能合理地分配和使用这些存储空间。当用户提出申请存储器空间时,存储管理必须根据申请者的要求,按一定的策略分析主存空间的使用情况,找出足够的空闲区域分配给申请者。当作业撤离或主动归还主存资源时,则存储管理要收回作业占用的主存空间或归还部分主存空间。主存的分配和回收的实现与主存储器的管理方式有关的,通过本实验帮助学生理解在可变分区管理方式下应怎样实现主存空间的分配和回收。
实验原理
模拟在可变分区管理方式下采用最先适应算法实现主存分配和回收。
(1)可变分区方式是按作业需要的主存空间大小来分割分区的。当要装入一个作业时,根据作业需要的主存量查看是否有足够的空闲空间,若有,则按需要量分割一个分区分配给该作业;若无,则作业不能装入。随着作业的装入、撤离,主存空间被分成许多个分区,有的分区被作业占用,而有的分区是空闲的。
为了说明哪些区是空闲的,可以用来装入新作业,必须要有一张空闲区说明表,格式如下:
起 址 长 度 状 态
第一栏 14 K 12 K 未 分 配
第二栏 32 K 96 K 未 分 配
其中,起址——指出一个空闲区的主存起始地址。
长度——指出从起始地址开始的一个连续空闲的长度。
状态——有两种状态,一种是“未分配”状态,指出对应的由起址指出的某个长度的区域是空闲区。
(2) 当有一个新作业要求装入主存时,必须查空闲区说明表,从中找出一个足够大的空闲区。有时找到的空闲区可能大于作业需要量,这时应把原来的空闲区变成两部分:一部分分给作业占用;另一部分又成为一个较小的空闲区。为了尽量减少由于分割造成的空闲区,而尽量保存高地址部分有较大的连续空闲区域,以利于大型作业的装入。为此,在空闲区说明表中,把每个空闲区按其地址顺序登记,即每个后继的空闲区其起始地址总是比前者大。
(3) 采用最先适应算法(顺序分配算法)分配主存空间。
按照作业的需要量,查空闲区说明表,顺序查看登记栏,找到第一个能满足要求的空闲区。当空闲区大于需要量时,一部分用来装入作业,另一部分仍为空闲区登记在空闲区说明表中。
由于本实验是模拟主存的分配,所以把主存区分配给作业后并不实际启动装入程序装入作业,而用输出“分配情况”来代替。
(4) 当一个作业执行结束撤离时,作业所占的区域应该归还,归还的区域如果与其它空闲区相邻,则应合成一个较大的空闲区,登记在空闲区说明表中。
(5) 请按最先适应算法设计主存分配和回收的程序。
测试数据
作业1申请300K,作业2申请100K,作业1释放300K,作业3申请150K,
作业4申请30K, 作业5申请40K, 作业6申请60K, 作业4释放30K。
请你为它们进行主存分配和回收,把空闲区说明表的初值以及每次分配或回收后的变化显示出来或打印出来。
完整代码+测试
import java.util.Comparator;
import java.util.LinkedList;
import java.util.List;
//因为要释放作业时 这个作业必须已经是申请过的不然会抛出一个异常
class HomeWorkNotFindException extends Exception {
public HomeWorkNotFindException(String message) {
super(message);
}
}
//还需要一个异常表示 内存放不下
class MemoryFullException extends Exception {
public MemoryFullException(String message) {
super(message);
}
}
//作业类 有一个id和要申请或者的内存大小 和要执行什么操作
class HomeWork {
public int id;
public int need;
public String doing;
public HomeWork(int id, int need, String doing) {
this.id = id;
this.need = need;
this.doing = doing;
}
}
//区域类 表示内存的起始地址和大小和状态
class Area {
public int homeWorkId;
public int indexBig;
public int areaSize;
public boolean state;
public Area(int homeWorkId, int indexBig, int areaSize, boolean state) {
this.homeWorkId = homeWorkId;
this.indexBig = indexBig;
this.areaSize = areaSize;
this.state = state;//true表示未分配 false表示已分配
}
@Override
public String toString() {
return indexBig + "k" + " " + areaSize + "k" + " " + (state ? "未分配" : "已分配");
}
}
//主存储器空间的分配和回收的一个类
//需要一个链表去记录所有已分配和未分配区域
//需要一个加作业的方法
//需要一个释放作业的方法
//需要一个打印空闲区域的一个链表
public class MemoryManagement {
private List<Area> list = new LinkedList<>();
public MemoryManagement() {
list.add(new Area(0, 0, 512, true));
}
//只需要把作业传进来 在这个类里会判断是要申请空间还是释放空间
public void implementWork(HomeWork homeWork) throws HomeWorkNotFindException, MemoryFullException {
if ("申请".equals(homeWork.doing)) {
apply(homeWork);
displayFreeArea();
} else {
if ("释放".equals(homeWork.doing)) {
free(homeWork);
displayFreeArea();
}
}
}
private void free(HomeWork homeWork) throws HomeWorkNotFindException {
for (Area a: this.list
) {
if (a.homeWorkId == homeWork.id) {
a.state = true;
for (int index = list.indexOf(a) - 1; index >= 0 && list.get(index).state; index--) {
Area area = list.get(index);
area.areaSize += a.areaSize;
list.remove(a);
a = area;
}
for (int index = list.indexOf(a) + 1; index < list.size() && list.get(index).state; index++) {
Area area = list.get(index);
a.areaSize += area.areaSize;
list.remove(area);
}
return;
}
}
//抛出一个异常
throw new HomeWorkNotFindException("未找到要释放的内存区域");
}
private void apply(HomeWork homeWork) throws MemoryFullException {
//申请的时候遍历区域链表找到未分配的并且可以放的下作业的区域 如果没找到就放在最后面
//但是此时肯可能会把未分配的一个区域变成俩个区域 一个表示已分配 一个表示未分配
//最后要记得排序区域链表
//区域状态true表示未分配 false表示已分配
for (Area a : this.list
) {
if (a.state && a.areaSize >= homeWork.need) {
//找到那个我们需要的区域
if (a.areaSize == homeWork.need) {
//空闲区域和需要的区域大小相等
a.homeWorkId = homeWork.id;
a.state = false;
} else {
Area areaTrue = new Area(homeWork.id, a.indexBig, homeWork.need, false);
Area areaFalse = new Area(homeWork.id, a.indexBig + homeWork.need, a.areaSize - homeWork.need, true);
list.remove(a);
list.add(areaTrue);
list.add(areaFalse);
}
this.list.sort(new Comparator<Area>() {
@Override
public int compare(Area o1, Area o2) {
return o1.indexBig - o2.indexBig;
}
});
return;
}
}
//如果最后一个空闲区域内存还是不够大
throw new MemoryFullException("内存放不下");
/* //此处说明链表里没找到合适位置就把他放到最后 此处有俩种情况 链表为空和链表不为空
if (this.list.isEmpty()) {
this.list.add(new Area(homeWork.id, 0, homeWork.need, false));
} else {
Area last = this.list.get(this.list.size() - 1);
this.list.add(new Area(homeWork.id, last.indexBig + last.areaSize, homeWork.need, false));
}
this.list.sort(new Comparator<Area>() {
@Override
public int compare(Area o1, Area o2) {
return o1.indexBig - o2.indexBig;
}
});*/
}
//打印空闲区域
public void displayFreeArea() {
System.out.println("======================");
System.out.println("起址" + " " + "长度" + " " + "状态");
for (Area a : this.list
) {
if (a.state) {
System.out.println(a.toString());
}
}
System.out.println("======================");
}
}
测试
public class MemoryTest {
public static void main(String[] args) {
MemoryManagement memoryManagement = new MemoryManagement();
//创建作业
HomeWork[] homeWorks = new HomeWork[8];
homeWorks[0] = new HomeWork(1, 300, "申请");
homeWorks[1] = new HomeWork(2, 100, "申请");
homeWorks[2] = new HomeWork(1, 300, "释放");
homeWorks[3] = new HomeWork(3, 150, "申请");
homeWorks[4] = new HomeWork(4, 30, "申请");
homeWorks[5] = new HomeWork(5, 40, "申请");
homeWorks[6] = new HomeWork(6, 60, "申请");
homeWorks[7] = new HomeWork(4, 30, "释放");
//
System.out.println("初始空闲说明表");
memoryManagement.displayFreeArea();
//执行作业
for (HomeWork h : homeWorks
) {
System.out.println();
System.out.println();
System.out.println("执行作业" + h.id + "任务是" + h.doing + h.need + "k");
try {
memoryManagement.implementWork(h);
} catch (HomeWorkNotFindException | MemoryFullException e) {
e.printStackTrace();
}
System.out.println("此时空闲列表如下:");
}
}
}
- 结果
初始空闲说明表
======================
起址 长度 状态
0k 512k 未分配
======================
执行作业1任务是申请300k
======================
起址 长度 状态
300k 212k 未分配
======================
执行作业2任务是申请100k
======================
起址 长度 状态
400k 112k 未分配
======================
执行作业1任务是释放300k
======================
起址 长度 状态
0k 300k 未分配
400k 112k 未分配
======================
执行作业3任务是申请150k
======================
起址 长度 状态
150k 150k 未分配
400k 112k 未分配
======================
执行作业4任务是申请30k
======================
起址 长度 状态
180k 120k 未分配
400k 112k 未分配
======================
执行作业5任务是申请40k
======================
起址 长度 状态
220k 80k 未分配
400k 112k 未分配
======================
执行作业6任务是申请60k
======================
起址 长度 状态
280k 20k 未分配
400k 112k 未分配
======================
执行作业4任务是释放30k
======================
起址 长度 状态
150k 30k 未分配
280k 20k 未分配
400k 112k 未分配
======================
Process finished with exit code 0