動態分割槽分配(基於Java語言的視覺化展示)
阿新 • • 發佈:2021-02-17
目的: 熟悉記憶體的分配與回收過程;理解在不同的管理方式下,如何實現記憶體空間的分配與回收;通過實驗,掌握動態分割槽分配方式中的資料結構、分配演算法、動態分割槽儲存管理方式其實現過程。
要求: 分別實現四種分配演算法:首次適應、迴圈首次適應、最佳適應和最壞適應。
(1)資料結構
採用連結串列表示記憶體使用情況,連結串列中的結點可以給出對應的某塊記憶體區域的資訊,如起始地址、大小、使用情況(是否空閒)、所裝入的程序名等。
- 設計一個空閒分割槽連結串列,用以表示當前記憶體使用情況,在進行記憶體分配時,系統優先使用空閒區低端的空間。(也可以設定兩個連結串列,一個是空閒分割槽,一個是已分配分割槽)
- 利用一個程序申請佇列以及程序完成後的釋放順序,實現主存的分配和回收。
(2)記憶體分配
- 動態輸入構造空閒區表,並顯示列印構造好的空閒分割槽表;
- 根據到達程序的申請,實施記憶體分配,並返回分配所得記憶體首址;
- 分配完後,調整空閒分割槽表(即扣除分配部分),並顯示調整後的空閒分割槽表;
- 若分配失敗,返回分配失敗資訊。
(3)記憶體回收
- 程序執行結束後,回收相應的記憶體,按記憶體回收的四種情況進行記憶體回收;
(4)輸入
- 除作業系統佔用的記憶體外,可用記憶體大小 n(整數);
- 程序申請佇列(輸入各程序名、申請的空間大小、到達時間、執行時間等,獲得記憶體後按先來先服務演算法排程執行)。
例如:假設初始狀態下,可用的記憶體空間為 640KB,並有下列的請求序列:
程序 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)結果