1. 程式人生 > 其它 >動態分割槽分配(基於Java語言的視覺化展示)

動態分割槽分配(基於Java語言的視覺化展示)

技術標籤:作業系統java作業系統記憶體管理演算法視覺化

目的: 熟悉記憶體的分配與回收過程;理解在不同的管理方式下,如何實現記憶體空間的分配與回收;通過實驗,掌握動態分割槽分配方式中的資料結構、分配演算法、動態分割槽儲存管理方式其實現過程。
要求: 分別實現四種分配演算法:首次適應、迴圈首次適應、最佳適應和最壞適應。

(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)結果
視覺化結果展示