目的: 熟悉内存的分配与回收过程;理解在不同的管理方式下,如何实现内存空间的分配与回收;通过实验,掌握动态分区分配方式中的数据结构、分配算法、动态分区存储管理方式其实现过程。
要求: 分别实现四种分配算法:首次适应、循环首次适应、最佳适应和最坏适应。
(1)数据结构
采用链表表示内存使用情况,链表中的结点可以给出对应的某块内存区域的信息,如起始地址、大小、使用情况(是否空闲)、所装入的进程名等。
- 设计一个空闲分区链表,用以表示当前内存使用情况,在进行内存分配时,系统优先使用空闲区低端的空间。(也可以设置两个链表,一个是空闲分区,一个是已分配分区)
- 利用一个进程申请队列以及进程完成后的释放顺序,实现主存的分配和回收。
(2)内存分配
- 动态输入构造空闲区表,并显示打印构造好的空闲分区表;
- 根据到达进程的申请,实施内存分配,并返回分配所得内存首址;
- 分配完后,调整空闲分区表(即扣除分配部分),并显示调整后的空闲分区表;
- 若分配失败,返回分配失败信息。
(3)内存回收
- 进程运行结束后,回收相应的内存,按内存回收的四种情况进行内存回收;
(4)输入
- 除操作系统占用的内存外,可用内存大小 n(整数);
- 进程申请队列(输入各进程名、申请的空间大小、到达时间、运行时间等,获得内存后按先来先服务算法调度运行)。
例如:假设初始状态下,可用的内存空间为 640KB,并有下列的请求序列:
进程 1,130KB,0,5
进程 2,60KB,3,6
进程 3,100KB,2,8
进程 2,60KB,5,10
进程 5,200KB,8,2
……
(5)实现
Job.java
package com.test;
import java.util.Objects;
/**
* @program: untitled
* @description: 作业类
* @author: YOUNG
* @create: 2020-12-04 16:21
*/
public class Job {
//起始地址
private int id;
private int size;
//剩余工作时间
private int time;
public int getTime() {
return time;
}
public int getId() {
return id;
}
public int getSize() {
return size;
}
public Job(int id, int size,int time) {
this.id = id;
this.size = size;
this.time = time;
System.out.println(this.toString());
}
public void run(){
if (this.time>0)
this.time-=1;
}
@Override
public boolean equals(Object o) {
if (this == o) return true;
if (o == null || getClass() != o.getClass()) return false;
Job job = (Job) o;
return id == job.id && size == job.size;
}
@Override
public int hashCode() {
return Objects.hash(id, size);
}
@Override
public String toString() {
return "Job{" +
"id=" + id +
", size=" + size +
", time=" + time +
'}';
}
}
Memory.java
package com.test;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.util.ArrayList;
import java.util.Comparator;
import java.util.LinkedList;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.Lock;
import java.util.concurrent.locks.ReentrantLock;
/**
* @program: untitled
* @description:
* @author: YOUNG
* @create: 2020-12-04 15:43
*/
public class Memory {
//内存大小
private final int size;
//空闲大小
private int unusedSize;
//已分配大小
private int usedSize;
//所有块头指针
private Block blockPointer;
//空闲块链表
private final LinkedList<Block> IdleLinkedList;
//已分配块链表
private final LinkedList<Block> AllocatedLinkedList;
//已经运行时间
private int time = 0;
//
private String flag;
private boolean startFlag = false;
private final Lock lock = new ReentrantLock();
private final Condition condition = lock.newCondition();
public Memory(int size) {
this.size = size;
this.unusedSize = size;
this.usedSize = 0;
Block firstBlock = new Block(size, 0);
this.blockPointer = firstBlock;
this.IdleLinkedList = new LinkedList<>();
IdleLinkedList.add(firstBlock);
// 第一次添加内存块只有一个没必要排序
// IdleLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
this.AllocatedLinkedList = new LinkedList<>();
}
public void start() {
new Thread(() -> {
//消亡内存块队列
ArrayList<Integer> blockIds = new ArrayList<>();
//作业准备队列
ArrayList<Job> readyJobs = new ArrayList<>();
int i = 3;
while (true) {
//更新页面
My.getOwm().updateUI();
//装载作业
if (time == 0)
readyJobs.add(new Job(1, 130, 5));
if (time == 3)
readyJobs.add(new Job(2, 60, 6));
if (time == 2)
readyJobs.add(new Job(3, 100, 8));
if (time == 5)
readyJobs.add(new Job(2, 60, 10));
if (time == 8)
readyJobs.add(new Job(5, 200, 12));
if (time == 12)
readyJobs.add(new Job(6, 150, 5));
if (time == 16)
readyJobs.add(new Job(7, 80, 5));
if (time == 19)
readyJobs.add(new Job(8, 80, 5));
//从准备队列将作业装入到内存块中
readyJobs.removeIf(job -> add(flag, job));
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
//第二次更新页面,显示装入的过程
My.getOwm().updateUI();
//运行1s
AllocatedLinkedList.forEach(block -> {
block.jobbing.run();
if (block.jobbing.getTime() == 0) {
blockIds.add(block.id);
}
});
blockIds.forEach(this::remove);
blockIds.clear();
try {
Thread.sleep(500);
} catch (InterruptedException e) {
e.printStackTrace();
}
time++;
if (AllocatedLinkedList.size() == 0)
if (i != 0)
i--;
else
break;
if (startFlag) {
My.getOwm().getNextButton().setEnabled(true);
lock.lock();
try {
condition.await();
} catch (InterruptedException e) {
e.printStackTrace();
}
lock.unlock();
}
}
My.getOwm().getChangeButton().setEnabled(true);
My.getOwm().getFFButton().setEnabled(true);
My.getOwm().getNFButton().setEnabled(true);
My.getOwm().getBFButton().setEnabled(true);
My.getOwm().getWFButton().setEnabled(true);
}).start();
}
//起始空闲块
// private Block initialIdleBlock;
//最终空闲块
// private Block finalIdleBlock;
//起始已分配块
// private Block initialAllocatedBlock;
//最终已分配块
// private Block finalAllocatedBlock;
//内存分区块
private class Block {
//id
private int id;
//起始地址
private int headAddress;
//大小
private int size;
//空闲状态
private boolean isFree;
//前驱指针
private Block front;
//后继指针
private Block next;
//作业
private Job jobbing;
public Block(Job jobbing, int headAddress) {
this.id = jobbing.getId();
this.size = jobbing.getSize();
this.isFree = false;
this.jobbing = jobbing;
this.headAddress = headAddress;
}
public Block(int size, int headAddress) {
this.size = size;
this.isFree = true;
this.headAddress = headAddress;
}
public void setJobbing(Job jobbing) {
this.id = jobbing.getId();
this.size = jobbing.getSize();
this.isFree = false;
this.jobbing = jobbing;
}
@Override
public String toString() {
return "Block{" +
"id=" + id +
", size=" + size +
", isFree=" + isFree +
", jobbing=" + jobbing +
'}';
}
}
public synchronized boolean add(String flag, Job job) {
//装入内存的作业大小小于等于剩余内存大小
if (job.getSize() <= this.unusedSize) {
if (flag.equals("FF") || flag.equals("NF")) {
for (Block block : IdleLinkedList) {
if (loadJob(job, block)) return true;
// if (block.size > job.getSize()) {//可用块大小大于作业大小
// //从可用块中分出作业大小的内存块,然后装入作业
// Block PreparedBlock = new Block(job, block.headAddress);
// //更新起始地址
// block.headAddress += PreparedBlock.size;
// block.size -= PreparedBlock.size;
// PreparedBlock.front = block.front;
// //无头结点的弊端
// if (block.front != null)
// block.front.next = PreparedBlock;
// block.front = PreparedBlock;
// PreparedBlock.next = block;
//
// AllocatedLinkedList.add(PreparedBlock);
// AllocatedLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
//
// //更新内存空闲大小和内存已分配大小
// updateUnusedSizeAndUsedSize(PreparedBlock, "add");
// //更新所有内存块头指针
// updateBlockPointer();
//
// return true;
// } else if (block.size == job.getSize()) {//可用块大小正好等于作业大小,直接装入
// //在foreach不应该remove元素,但这里可以使用,是一个陷阱
// IdleLinkedList.remove(block);
// block.setJobbing(job);
// AllocatedLinkedList.add(block);
// AllocatedLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
//
//
// //更新内存空闲大小和内存已分配大小
// updateUnusedSizeAndUsedSize(block, "add");
// //更新所有内存块头指针
// updateBlockPointer();
//
// return true;
// }
}
return false;
} else if (flag.equals("BF") || flag.equals("WF")) {
Block block = null;
//最佳:距离应该大于总内存大小
//最坏:距离应该小于0
int distance = flag.equals("BF") ? size + 1 : -1;
for (Block reBlock : IdleLinkedList) {
if (reBlock.size >= job.getSize()) {
//块大小>=作业大小,块可用
if (flag.equals("BF")) {
//是BF算法
if (reBlock.size - job.getSize() < distance) {
block = reBlock;
distance = block.size - job.getSize();
}
} else {
//只能是WF算法
if (reBlock.size - job.getSize() > distance) {
block = reBlock;
distance = block.size - job.getSize();
}
}
}
}
if (block != null) {
System.out.println(block.size);
return loadJob(job, block);
} else
return false;
}
}
return false;
}
private boolean loadJob(Job job, Block block) {
if (block.size > job.getSize()) {
//可用块大小大于作业大小
//从可用块中分出作业大小的内存块,然后装入作业
Block PreparedBlock = new Block(job, block.headAddress);
//更新起始地址
block.headAddress += PreparedBlock.size;
block.size -= PreparedBlock.size;
PreparedBlock.front = block.front;
//无头结点的弊端
if (block.front != null)
block.front.next = PreparedBlock;
block.front = PreparedBlock;
PreparedBlock.next = block;
AllocatedLinkedList.add(PreparedBlock);
AllocatedLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
//更新内存空闲大小和内存已分配大小
updateUnusedSizeAndUsedSize(PreparedBlock, "add");
//更新所有内存块头指针
updateBlockPointer();
return true;
} else if (block.size == job.getSize()) {
//可用块大小正好等于作业大小,直接装入
//在foreach不应该remove元素,但这里可以使用,是一个陷阱
IdleLinkedList.remove(block);
block.setJobbing(job);
AllocatedLinkedList.add(block);
AllocatedLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
//更新内存空闲大小和内存已分配大小
updateUnusedSizeAndUsedSize(block, "add");
//更新所有内存块头指针
updateBlockPointer();
return true;
}
return false;
}
public synchronized boolean remove(int id) {
for (Block block : AllocatedLinkedList) {
if (block.id == id) {
AllocatedLinkedList.remove(block);
//更新内存信息
updateUnusedSizeAndUsedSize(block, "remove");
block.id = 0;
block.jobbing = null;
block.isFree = true;
//合并空闲分区
if (block.front != null && block.front.isFree) {
block.front.size += block.size;
//block.front.next=block.next;
if (block.next != null && block.next.isFree) {
//左右块都是空闲块
IdleLinkedList.remove(block.next);
block.front.size += block.next.size;
block.front.next = block.next.next;
if (block.next.next != null) {
block.next.next.front = block.front;
}
block.next.next = null;
block.next.front = null;
block.next = null;
block.front = null;
return true;
} else if (block.next != null)
block.next.front = block.front;
///左块空闲,右块不是
block.front.next = block.next;
block.next = null;
block.front = null;
return true;
///
} else if (block.next != null && block.next.isFree) {
//右块空闲,左块不是
IdleLinkedList.remove(block.next);
block.size += block.next.size;
Block p = block.next;
block.next = p.next;
if (p.next != null) {
p.next.front = block;
}
IdleLinkedList.add(block);
if (flag != null && flag.equals("FF"))
IdleLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
p.next = null;
p.front = null;
return true;
} else {
//左右都不是空闲块
IdleLinkedList.add(block);
if (flag != null && flag.equals("FF"))
IdleLinkedList.sort(Comparator.comparingInt(reBlock -> reBlock.headAddress));
return true;
}
}
}
return false;
}
private void updateUnusedSizeAndUsedSize(Block block, String flag) {
if (flag.equals("add")) {
this.usedSize += block.size;
this.unusedSize -= block.size;
} else if (flag.equals("remove")) {
this.usedSize -= block.size;
this.unusedSize += block.size;
}
}
private void updateBlockPointer() {
if (blockPointer.front != null)
// while (blockPointer.front!=null)
this.blockPointer = blockPointer.front;
}
public Image drawImage() {
// 创建内存图像
int width = this.size + 5 + 5, height = 150 + 5 + 5;
BufferedImage image = new BufferedImage(width, height + 20 * 2, BufferedImage.TYPE_INT_RGB);
Graphics g = image.getGraphics();
// 填充矩形区域
g.setColor(new Color(255, 255, 255));
g.fillRect(0, 0, width, height + 20 * 2);
//画外边框
g.setColor(new Color(0, 0, 0));
g.drawRect(1, 1, width - 2, height - 2);
//画内存块
Block p = blockPointer;
int x = 5;
while (p != null) {
if (p.isFree)
g.setColor(new Color(120, 190, 60));
else
g.setColor(new Color(255, 155, 155));
g.fillRect(x, 5, p.size - 1, height - 10);
g.setColor(new Color(0, 0, 0));
g.fillRect(x + p.size - 1, 5, 1, height - 10);
//写内存块大小
g.drawString(p.size + "KB", x + 1, (height - 10) / 2 + 5);
//写内存块首地址
if (p.isFree)
g.drawString(p.headAddress + "", x + 1, 15 + 1);
else {
g.setColor(new Color(18, 80, 11));
g.drawString(p.headAddress + ": job" + p.jobbing.getId(), x + 1, 15 + 1);
g.drawString(p.jobbing.getTime() + "s", x + 1, 15 + 1 + 20);
}
x += p.size;
p = p.next;
}
//画内存大小
g.drawString("used:" + this.usedSize + "KB / " + "size:" + this.size + "KB", width - 150, height + 20);
g.drawString("runtime:" + this.time + 's', width - 100, height + 20 * 2);
g.dispose();
return image;
}
public void setFlag(String flag) {
this.flag = flag;
}
public Condition getCondition() {
return condition;
}
public Lock getLock() {
return lock;
}
public void setStartFlag(boolean startFlag) {
this.startFlag = startFlag;
}
}
My.java
package com.test;
import javax.swing.*;
import java.awt.*;
/**
* @program: untitled
* @description:
* @author: YOUNG
* @create: 2020-12-04 15:44
*/
public class My {
private static My my;
private final JFrame jFrame = new JFrame("动态内存分区");
private final Box centerBox = Box.createVerticalBox();
private final Box southBox = Box.createVerticalBox();
private final JPanel southJPanel = new JPanel(new GridLayout(3,1));
private final JPanel centerJPanel = new JPanel(new GridLayout(2,1));
private final JPanel jobJPanel = new JPanel(new GridLayout(1,5));
private final JPanel buttonJPanel = new JPanel(new GridLayout(1,4));
private final JPanel changeButtonJPanel = new JPanel(new GridLayout(1,2));
private final JPanel imagePanel = new JPanel();
private final JButton FFButton = new JButton("首次适应");
private final JButton NFButton = new JButton("循环首次适应");
private final JButton BFButton = new JButton("最佳适应");
private final JButton WFButton = new JButton("最坏适应");
private final JButton okJobButton = new JButton("创建作业");
private final JButton changeButton = new JButton("自动演示");
private final JButton nextButton = new JButton("下一步");
private final JLabel jobIdLabel = new JLabel("作业ID:");
private final JLabel jobSizeLabel = new JLabel("作业大小:");
private final TextArea centerTextArea = new TextArea ("0,new Job(name:1, size:130, runtime:5)\n" +
"3,new Job(name:2, size:60, runtime:6)\n" +
"2,new Job(name:3, size:100, runtime:8)\n" +
"5,new Job(name:2,size: 60, runtime:10)\n" +
"8,new Job(name:5, size:200, runtime:12)\n" +
"12,new Job(name:6, size:150,runtime:5)\n" +
"16,new Job(name:7, size:80, runtime:5)\n" +
"19,new Job(name:8, size:80, runtime:5)\n");
private final JTextField jobIdTextField = new JTextField ("");
private final JTextField jobSizeTextField = new JTextField ("");
//默认可以不生成对象,为了防止程序崩溃,先搞一个
private Memory memory = new Memory(640);
private boolean model =false;
public Memory getMemory() {
return memory;
}
private My(){
};
public static My getOwm(){
if (my==null)
my = new My();
return my;
}
public void init() {
// imagePanel.add(new JLabel(new ImageIcon(memory.drawImage())));
jFrame.setBounds(0, 0, 1920-500, 700);
centerJPanel.add(imagePanel);
centerJPanel.add(centerTextArea);
centerBox.add(centerJPanel);
jFrame.add(centerBox, BorderLayout.CENTER);
jobJPanel.add(jobIdLabel);
jobJPanel.add(jobIdTextField);
jobJPanel.add(jobSizeLabel);
jobJPanel.add(jobSizeTextField);
jobJPanel.add(okJobButton);
FFButton.addActionListener(e -> {
memory = new Memory(640);
changeButton.setEnabled(false);
FFButton.setEnabled(false);
NFButton.setEnabled(false);
BFButton.setEnabled(false);
WFButton.setEnabled(false);
memory.setStartFlag(model);
memory.setFlag("FF");
memory.start();
});
NFButton.addActionListener(e -> {
memory = new Memory(640);
changeButton.setEnabled(false);
FFButton.setEnabled(false);
NFButton.setEnabled(false);
BFButton.setEnabled(false);
WFButton.setEnabled(false);
memory.setStartFlag(model);
memory.setFlag("NF");
memory.start();
});
BFButton.addActionListener(e -> {
memory = new Memory(640);
changeButton.setEnabled(false);
FFButton.setEnabled(false);
NFButton.setEnabled(false);
BFButton.setEnabled(false);
WFButton.setEnabled(false);
memory.setStartFlag(model);
memory.setFlag("BF");
memory.start();
});
WFButton.addActionListener(e -> {
memory = new Memory(640);
changeButton.setEnabled(false);
FFButton.setEnabled(false);
NFButton.setEnabled(false);
BFButton.setEnabled(false);
WFButton.setEnabled(false);
memory.setStartFlag(model);
memory.setFlag("WF");
memory.start();
});
changeButton.addActionListener(e -> {
if(e.getActionCommand().equals("自动演示")&&!model){
changeButton.setText("手动演示");
nextButton.setEnabled(true);
model=true;
}else if(e.getActionCommand().equals("手动演示")&&model) {
changeButton.setText("自动演示");
nextButton.setEnabled(false);
model=false;
}
});
nextButton.setEnabled(false);
nextButton.addActionListener(e -> {
memory.getLock().lock();
memory.getCondition().signalAll();
memory.getLock().unlock();
nextButton.setEnabled(false);
});
buttonJPanel.add(FFButton);
buttonJPanel.add(NFButton);
buttonJPanel.add(BFButton);
buttonJPanel.add(WFButton);
changeButtonJPanel.add(changeButton);
changeButtonJPanel.add(nextButton);
southJPanel.add(jobJPanel);
southJPanel.add(buttonJPanel);
southJPanel.add(changeButtonJPanel);
southBox.add(southJPanel);
jFrame.add(southBox, BorderLayout.SOUTH);
jFrame.setVisible(true);
jFrame.setDefaultCloseOperation(WindowConstants.EXIT_ON_CLOSE);
}
public void updateUI(){
imagePanel.removeAll();
imagePanel.add(new JLabel(new ImageIcon(memory.drawImage())));
imagePanel.updateUI();
}
public JButton getFFButton() {
return FFButton;
}
public JButton getNFButton() {
return NFButton;
}
public JButton getBFButton() {
return BFButton;
}
public JButton getWFButton() {
return WFButton;
}
public JButton getChangeButton() {
return changeButton;
}
public JButton getNextButton() {
return nextButton;
}
public static void main(String[] args) {
getOwm().init();
}
}
(6)结果