精华内容
下载资源
问答
  • 银行家算法--进程调度算法--内存分配算法java实现
  • 内存的作用 内存是计算机的一个重要组成部分,它的主要作用在于配合 CPU 的高速运转,使得计算机的运行速度得到大大地提升 我们应该知道,计算机上的一切都是程序,我们使用计算机其实就是在运行计算机上的各种...

    一. 内存的作用

    内存是计算机的一个重要组成部分,它的主要作用在于配合 CPU 的高速运转,使得计算机的运行速度得到大大地提升
    我们应该知道,计算机上的一切都是程序,我们使用计算机其实就是在运行计算机上的各种程序,而这些程序都存储在我们的硬盘中(外存),硬盘中的数据内容是几乎可以永久存储的但是 它的读取速度相较于 CPU 的处理速度是十分缓慢的
    如果没有内存,CPU 在处理完一段程序后,要空闲很长一段时间等待硬盘继续传送数据,这样一来,极大地降低了 CPU 的效率
    而内存由于其构造原理与硬盘不同,它的读写速度非常快(虽然不及 CPU,但可以远高于硬盘),但是它内部的数据断电后就会消失,不具有永久存储性,因此,内存的主要作用就相当于 CPU 与硬盘之间的中转站,内存中会暂存即将要执行的程序,等待着 CPU 的调度

    二. 内存分配

    基于内存的工作原理,你一定想问:既然内存速度那么快,为什么不把硬盘中的所有数据全部放入内存等待 CPU 调度呢?
    因为内存不仅读取速度是硬盘的很多倍,制造成本也远高于硬盘,所以必须省着点用啊!
    那么新的问题来了,内存空间有限,那么在有限的空间中该怎么存取数据呢?这就是内存的分配算法了

    内存分配算法,大体来说分为:连续式分配 与 非连续式分配
    顾名思义连续式分配就是把所以要执行的程序 完整的,有序的 存入内存,连续式分配又可以分为固定分区分配 和 动态分区分配
    非连续式分配就是把要执行的程序按照一定规则进行拆分,显然这样更有效率,现在的操作系统通常也都是采用这种方式分配内存

    关于内存的原理部分本文只讲到这里,本文主要关注动态分区分配算法

    三. 动态分区分配

    所谓动态分区分配,就是指内存在初始时不会划分区域,而是会在进程装入时,根据所要装入的进程大小动态地对内存空间进行划分,以提高内存空间利用率,降低碎片的大小
    动态分区分配算法有以下四种:

    1. 首次适应算法(First Fit)

    空闲分区以地址递增的次序链接。分配内存时顺序查找,找到大小满足要求的第一个空闲分区就进行分配
    这里写图片描述

    2. 邻近适应算法(Next Fit)

    又称循环首次适应法,由首次适应法演变而成,不同之处是分配内存时从上一次查找结束的位置开始继续查找
    这里写图片描述

    3. 最佳适应算法(Best Fit)

    空闲分区按容量递增形成分区链,找到第一个能满足要求的空闲分区就进行分配
    这里写图片描述

    4. 最坏适应算法(Next Fit)

    又称最大适应算法(Largest Fit),空闲分区以容量递减的次序链接,找到第一个能满足要求的空闲分区(也就是最大的分区)就进行分配
    这里写图片描述

    四. 代码实现

    Source Code

    package com.dht.memory;
    
    import java.util.LinkedList;
    import java.util.Scanner;
    
    /**
     * 内存类
     * @author dht925nerd@126.com
     */
    public class Memory{
        /**
         * 内存大小
         */
        private int size;
        /**
         * 最小剩余分区大小
         */
        private static final int MIN_SIZE = 5;
        /**
         * 内存分区
         */
        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;
            }
        }
    
        /**
         * 默认内存大小为 100 KB
         */
        public Memory(){
            this.size = 100;
            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));
        }
    
        /**
         * 内存分配
         * @param size 指定需要分配的大小
         */
        public void allocation(int size){
            System.out.println("1.FirstFit 2.NextFit 3.BestFit 4.WorstFit");
            System.out.print("请选择分配算法:");
            Scanner in = new Scanner(System.in);
            int algorithm = in.nextInt();
            switch (algorithm){
                case 1:
                    fristFit(size);break;
                case 2:
                    nextFit(size);break;
                case 3:
                    bestFit(size);break;
                case 4:
                    worstFit(size);break;
                default:
                    System.out.println("请重新选择!");
            }
        }
    
        /**
         * 首次适应算法
         * @param size 指定需要分配的大小
         */
        private void fristFit(int size){
            //遍历分区链表
            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("无可用内存空间!");
        }
    
        /**
         * 循环首次适应算法
         * @param size 指定需要分配的大小
         */
        private void nextFit(int size){
            //从上次分配空闲区位置开始遍历分区链表
            Zone tmp = zones.get(pointer);
            if (tmp.isFree && (tmp.size > size)){
                doAllocation(size, pointer, tmp);
                return;
            }
            int len = zones.size();
            int i = (pointer + 1) % len;
            for (; i != pointer; i = (i+1) % len){
                tmp = zones.get(i);
                //找到可用分区(空闲且大小足够)
                if (tmp.isFree && (tmp.size > size)){
                    doAllocation(size, i, tmp);
                    return;
                }
            }
            //遍历结束后未找到可用分区, 则内存分配失败
            System.out.println("无可用内存空间!");
        }
    
        /**
         * 最佳适应算法
         * @param size 指定需要分配的大小
         */
        private 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));
            }
        }
    
        /**
         * 最坏适应算法
         * @param size 指定需要分配的大小
         */
        private void worstFit(int size){
            int flag = -1;
            int max = 0;
            for (pointer = 0; pointer < zones.size(); pointer++){
                Zone tmp = zones.get(pointer);
                if (tmp.isFree && (tmp.size > size)){
                    if (max < tmp.size - size){
                        max = tmp.size - size;
                        flag = pointer;
                    }
                }
            }
            if (flag == -1){
                System.out.println("无可用内存空间!");
            }else {
                doAllocation(size, flag, zones.get(flag));
            }
        }
    
        /**
         * 执行分配
         * @param size 申请大小
         * @param location 当前可用分区位置
         * @param tmp 可用空闲区
         */
        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 内存!");
        }
    
        /**
         * 内存回收
         * @param id 指定要回收的分区好号
         */
        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;
            }
            //如果回收分区不是尾分区且后一个分区为空闲, 则与后一个分区合并
            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("------------------------------------");
            System.out.println("分区编号\t分区始址\t分区大小\t空闲状态\t");
            System.out.println("------------------------------------");
            for (int i = 0; i < zones.size(); i++){
                Zone tmp = zones.get(i);
                System.out.println(i + "\t\t" + tmp.head + "\t\t" +
                                    tmp.size + "  \t" + tmp.isFree);
            }
            System.out.println("------------------------------------");
        }
    }
    展开全文
  • 前言 首次适应算法(FF,first fit)是内存基于顺序搜索的动态分配分区...若从链首直至链尾都不能找到一个能满足要求的分区,则表明系统中已没有足够大的内存分配给该进程,内存分配失败,返回。 该算法倾向于优

    前言
      首次适应算法(FF,first fit)是内存基于顺序搜索的动态分配分区算法,在分配内存时,从链首开始顺序查找,直至找到一个大小能满足要求的空闲分区为止,然后在按照作业的大小从该分区中划出一块内存空间,分配给请求者,余下的空闲分区仍留在空闲链中。若从链首直至链尾都不能找到一个能满足要求的分区,则表明系统中已没有足够大的内存分配给该进程,内存分配失败,返回。
      该算法倾向于优先利用内存中低地址部分的空闲分区,从而保留了高地址部分不断被划分。这为以后到达的大作业分配大的的内存空间创造了条件。其缺点是低地址部分不断被划分,会留下许多难以利用的、很小的空闲分区,称为碎片。而每次查找又都是从低地址部分开始的,这无疑又会增加查找可用空闲分区时的开销。
      这里用JAVA写了一个用首次适应算法来模拟内存分配与回收的程序并配有界面,更加直观的显示了首次适应算法的分配过程。
      功能主要有三个模块。第一个内存分配模块,用户根据自己的需要输入进程数,然后分配,每次分配都会有相应的模块号和模块大小情况显示出来再界面上,我们这里模拟的内存容量是十个,所以最多只能分配十个进程。第二个是释放内存模块,在分配时我们已经为每次分配的时候加上了对应的内存块号和内存大小,然后根据模块号,释放掉分配时的内存的大小。第三个是清空内存模块,这里就一个功能就是将内存块回归到初始状态,相当于重启了电脑一样的,内存的东西不在保留,用户可以在根据需要重新分配。
    功能结构图:

    代码如下:

    import java.awt.BorderLayout;
    import java.awt.Color;
    import java.awt.FlowLayout;
    import java.awt.Font;
    import java.awt.GridLayout;
    import java.awt.Label;
    import java.awt.event.ActionEvent;
    import java.awt.event.ActionListener;
    
    import javax.swing.JButton;
    import javax.swing.JFrame;
    import javax.swing.JLabel;
    import javax.swing.JOptionPane;
    import javax.swing.JPanel;
    import javax.swing.JTextArea;
    import javax.swing.JTextField;
    
    public class Memory extends JFrame {
        protected JTextField blank0,blank1,blank2,blank3,
                             blank4,blank5,blank6,blank7,
                             blank8,blank9;//定义10个进程块
        protected JTextField applyMemTF,releaseMemTF;
        protected JTextArea showMemStatusTF;
        protected JButton applyMemButton,releaseMemButton,emptyMemButton;
    
        int[] processBlock = new int[10];//表示进程块
        int[] processBlockStartAdd = new int[10];//表示存储起始地址
        int[] processBlockLength = new int[10];//表示存储进程长度
    
        public Memory() {
            JPanel p1 = new JPanel(new GridLayout(3,2,5,2));
            p1.add(applyMemButton = new JButton("申请(大小)"));
            p1.add(applyMemTF = new JTextField(3));
            p1.add(releaseMemButton = new JButton("释放(块号)"));
            p1.add(releaseMemTF = new JTextField(3));
            p1.add(new Label("\t内存分配情况"));  
    
            JPanel p2 = new JPanel(new GridLayout(2,1,2,2));
            p2.add(p1);
            p2.add(showMemStatusTF = new JTextArea());
    
            JPanel p3 = new JPanel(new GridLayout(11,1,20,0));
            p3.add(new JLabel("内存容量为10"));
            p3.add(blank0 = new JTextField(3));
            p3.add(blank1 = new JTextField(3));
            p3.add(blank2 = new JTextField(3));
            p3.add(blank3 = new JTextField(3));
            p3.add(blank4 = new JTextField(3));
            p3.add(blank5 = new JTextField(3));
            p3.add(blank6 = new JTextField(3));
            p3.add(blank7 = new JTextField(3));
            p3.add(blank8 = new JTextField(3));
            p3.add(blank9 = new JTextField(3));
    
            JPanel p4 = new JPanel(new BorderLayout(3,3));
            p4.add(p2,BorderLayout.WEST);
            p4.add(p3,BorderLayout.CENTER);
    
            JPanel p5 = new JPanel(new FlowLayout());
            p5.add(p4);
            p5.add(emptyMemButton = new JButton("清空内存"),BorderLayout.EAST);
    
            setLayout(new FlowLayout(FlowLayout.CENTER,10,20));
            this.getContentPane().add(p5);
    
            Font font1 = new Font("SansSerif",Font.BOLD,16);
            applyMemTF.setFont(font1);
            releaseMemTF.setFont(font1);
            showMemStatusTF.setFont(font1); 
    
            applyMemButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    int n = Integer.parseInt(applyMemTF.getText());//进程块的大小
                    if(n > 10 || n <0){
                        JOptionPane.showMessageDialog(null,"进程大小违规,请重新输入!");
                    }
    
                    outer://向内存中添加进程    
                    for(int i = 0;i < 10; i++ ){//向内存中添加进程
                        if(processBlock[i] == 0 && Sum(processBlock,i,n) == 0){
                            processBlockStartAdd[i] = i;//存储起始地址
                            processBlockLength[i] = n;//存储进程长度
    
                            for(int ss = i;ss < (i + n);ss++)
                                processBlock[ss] = 1;//找到合适的位置,置1
                            colorr();
                            JOptionPane.showMessageDialog(null,"成功分配到内存!");
                            showMemStatusTF.append("块号:" + processBlockStartAdd[i] + " 起始位置:" +
                                    processBlockStartAdd[i] + "大小: " + processBlockLength[i] +"\n");
                            break outer;
                        }
                        if(i == 9){
                            JOptionPane.showMessageDialog(null,"内存不足,请等待...");
                            break outer;
                        }
                    }
                }
            });
            //释放内存按钮监听  
            releaseMemButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    int m = Integer.parseInt(releaseMemTF.getText());//进程块的起始位置和长度
                    for(int ff = m;ff < (m + processBlockLength[m]);ff++){
                        processBlock[ff] = 0;
                    }
                    processBlockStartAdd[m] = 0;
                    processBlockLength[m] = 0;
                    colorr();
    
                    showMemStatusTF.setText("");
    
                    for(int bb = 0;bb < 10; bb++){
                        if(processBlockLength[bb] != 0)
                            showMemStatusTF.append("块号: " + processBlock[bb] + "起始位置:" + 
                                    processBlockStartAdd[bb] + "大小: "+ processBlockLength[bb] + "\n");
                    }
                }
            });
            //清空内存按钮监听
            emptyMemButton.addActionListener(new ActionListener() {
                public void actionPerformed(ActionEvent e) {
                    for(int cc = 0;cc < 10;cc++)
                        processBlock[cc] = 0;
                    colorr();
    
                    applyMemTF.setText("");
                    releaseMemTF.setText("");
                    showMemStatusTF.setText("");
                }
            });
        }
    
        //判断内存空间是否足够
        public int Sum(int[] pp,int mm,int k){
            int sum = 0;
            if((mm + k) <= 10){
                for(int zz = mm;zz < (mm + k);zz++)
                    sum+=pp[zz];
            }
            else {
                sum = 1;
            }
    
            return sum;
        }
    
        //内存与processBlock数组相对应,占用颜色为绿色,空白为蓝色    
        public void colorr(){
    
            if(processBlock[0]==1)
                blank0.setBackground(Color.GREEN);
            else 
                blank0.setBackground(Color.WHITE);
    
            if(processBlock[1]==1)
                blank1.setBackground(Color.GREEN);
            else 
                blank1.setBackground(Color.WHITE);
    
            if(processBlock[2]==1)
                blank2.setBackground(Color.GREEN);
            else 
                blank2.setBackground(Color.WHITE);
    
            if(processBlock[3]==1)
                blank3.setBackground(Color.GREEN);
            else 
                blank3.setBackground(Color.WHITE);
    
            if(processBlock[4]==1)
                blank4.setBackground(Color.GREEN);
            else 
                blank4.setBackground(Color.WHITE);
    
            if(processBlock[5]==1)
                blank5.setBackground(Color.GREEN);
            else 
                blank5.setBackground(Color.WHITE);
    
            if(processBlock[6]==1)
                blank6.setBackground(Color.GREEN);
            else 
                blank6.setBackground(Color.WHITE);
    
            if(processBlock[7]==1)
                blank7.setBackground(Color.GREEN);
            else 
                blank7.setBackground(Color.WHITE);
    
            if(processBlock[8]==1)
                blank8.setBackground(Color.GREEN);
            else 
                blank8.setBackground(Color.WHITE);
    
            if(processBlock[9]==1)
                blank9.setBackground(Color.GREEN);
            else 
                blank9.setBackground(Color.WHITE);
        }
    
        public static void main(String[] args){
            Memory frame = new Memory();
            frame.setTitle("内存模拟分配与回收——首次适应算法");
            frame.setSize(500,400);
            frame.setLocationRelativeTo(null);
            frame.setDefaultCloseOperation(JFrame.EXIT_ON_CLOSE);
            frame.setVisible(true);
        }
    }

      首先定义所需要的变量,定义十个变量表示十个进程,接下来就是在内存中为他们分配内存。定义了两个文本框,分别表示用来向内存申请多少块内存以及释放多少块内存。定义个一个显示文本域,用来及时显示内存中分配的情况和释放的情况。定义三个按钮,分别是申请内存按钮、释放内存按钮、清空内存按钮。稍后我们为他们添加监听事件来产生相应的效果。然后定义三个整形数组,大小都为10,一个用来表示进程,一个用来表示进程的存储起始地址,一个用来表示进程的长度。
      我们还要做一个程序的界面,在这里我们已经为相应的按钮添加的相应的监听的事件,文本域和文本框也做了相应的设置,详情请见源代码,程序的界面图如下:
    程序界面图
      我们在申请大小的文本框中输入要分配的进程块,这里输入的是一个字符型的数字,将它解析成整形的数字,然后我们在进行判断,因为我们这里模拟的内存容量为10,所以在输入数字的时候如果大于10或者小于0就违反了进程规定,需要重新输入。输入正确就开始向内存中申请分配内存了,首先看该进程数是否为空,然后我们好重新定义了一个判断内存释放足够的方法, 如果该内存块又为空,内存空间又符合输入的进程数就为它分配,分配之后将进程的数组置为1,然后调用颜色改变的方法,该方法定义了如果该内存的数组的值为1线显示绿色,如果是0就置为白色,就是直观的显示内存的分配情况。再在“内存分配情况”的文本域中打印出内存的相应情况,块号、起始位置、大小的相关数据,这样一次内存的一次分配情况就完成了。
      分配之后,内存容量就会产生相应的效果,如果申请的数量大于剩余的的容量的话就会出现内存容量不足的警告,这时候就需要释放内存。在释放内存的文本框中输入要释放的内存块号,同样输入的数字是字符型的需要将它转换成整形,然后在根据输入的内存块号释放掉对应的内存块。模拟的过程是将相应的进程数组置、进程块的起始地址和进程的长度置为0,然后调用颜色改变的方法,将进程数组为0的块的颜色改成白色,再将内存分配情况的文本域的情况撤销掉,重新打印内存分配情况。这样释放内存的步骤就完成了。
      经过多次的分配与释放之后可能就会产生一些碎片,即使内存的总容量大于要分配的内存容量,但是因为他们是不连续的,分配时候还是会分配失败,这时候我们就可以将内存清空,重新分配内存。清空内存模拟过成比上面的两个模拟都要简单很多,就是将进程的数组的情况用一个循环从0开始全部置为0,然后调用颜色改变的方法将颜色全都变为绿色,再将申请大小文本框、释放内存文本框、内存分配情况文本域全都置为空就可以了,这样也就是将内存清空的情况模拟过程完成了。
      接下来我们来看操作的一些结果:
      我们在申请内存框输入3,然后点击“申请(大小)”按钮,结果如下:
      这里写图片描述这里写图片描述
       可以看到我们已经成功从内存中成功申请到了3块内存。继续在内存分配文本框中输入4,结果如下:
      这里写图片描述这里写图片描述
      可以看到我们也申请成功了,我们继续在内存分配分本框中输入4,观察结果如下:
    这里写图片描述
    这里写图片描述
      这次我们申请失败了,原因肯定就是内存不够用了。接下来我们在“释放(块号)”文本框中输入:3,将块号3释放掉,观察结果:
    这里写图片描述
      可以看到我们已经成功将块号为3,大小为4的内存块成功释放点。接下来,点击“清空内存按钮”,观察结果:
    这里写图片描述
    点击了之后我们回到了初始状态,就可以继续分配内存了。

    展开全文
  • Java语言实现《操作系统》课程中“动态内存分配”实验的设计,采用首次使用算法(FIrst Fit)。
  • 内存分配方式与内存分配算法

    千次阅读 2018-03-14 20:24:56
    内存分配算法,其实就是:有一大块空闲的资源,如何合理地分配资源?内存分配的思想可以用到很多其他的领域。比如Java虚拟机是如何将内存分配与回收的?再比如文件系统是如何将磁盘块分配与回收的?其本质就是如何把...

    内存分配方式有两种,连续内存分配方式和离散内存分配方式。不同的分配方式又有不同的分配算法。

    内存分配算法,其实就是:有一大块空闲的资源,如何合理地分配资源?内存分配的思想可以用到很多其他的领域。比如Java虚拟机是如何将内存分配与回收的?再比如文件系统是如何将磁盘块分配与回收的?其本质就是如何把空闲的资源分配出去,分配之后又如何回收?目标就是分配快,回收也快,而且还不浪费。那么,就需要根据资源的特点、以及应用场景做权衡从而选择何种方式进行分配与回收。

    ①连续内存分配方式

    1)固定分区分配

    将内存划分成若干个固定大小的块。将程序装入块中即可。内存划分成各个块之后,块大小不再改变。当然,划分块的方式有:所有的块大小相等;划分的块大小不相等。

    这种方式,在实际的内存分配之前,就已经知道了所有的内存块大小了。

    2)动态分区分配

    需要一个空闲表 或者 空闲链 来记录目前系统中空间的内存区域。在内存分配时,需要查找空间表或空闲链找到一块内存分配给当前进程。

    动态分区分配算法:

    a)首次适应法

    b)循环首次适应法

    c)最佳适应法

    d)最坏适应法

    e)快速适应法

    3)可重定位分区分配

    说白了,就是增加了内存移动的功能。由于若干次内存分配与回收之后,各个空闲的内存块不连续了。通过“重定位”,将已经分配的内存“紧凑”在一块(就类似于JVM垃圾回收中的复制算法)从而空出一大块空闲的内存出来。

    ”紧凑“是需要开销的,比如需要重新计算 地址,这也为什么JVM垃圾回收会导致STW的原因。

    而离散分配方式–不管是分页还是分段,都是直接将程序放到各个离散的页中。从而就不存在“紧凑”一说了。

    连续内存分配方式涉及两种操作:内存分配操作 和 内存回收操作

    ②离散内存分配方式

    内存资源是有限的,程序要运行,必须得加载到内存。如果内存已经满了,而现在又有新的程序要运行,怎么办?—SWAP

    把当前不用的程序(数据)先换出内存,从而就有空间 加载当前需要运行的程序的一部分数据进入内存,这样大大提高了内存的利用率。

    由于牵涉到换入与换出,前面的连续内存分配方式就有点不适用了。因为,最明显的一个问题:对于连续内存分配方式,究竟换出哪部分数据呢?

    而这种只装入部分”数据”就可以使程序运行的机制,就是虚拟存储器的本质。

    1)分页存储管理

    将进程的逻辑地址空间分成若干大小相等的页面;同时,也将物理内存分成相等大小的页面(称为块或frame)。在为进程分配内存时,以块为单位将进程的若干页 可以 装入到内存中多个不邻接的物理块中。

    从上可以看出:“离散” 体现在:进程在内存中分配的空间(物理块)是不连续的。而对于连续分配方式,进程在内存的分配的空间是连续的。

    现在考虑32位系统,每个物理块的大小为4KB。如何把逻辑地址 转换成 物理地址?

    对每个进程而言,都有着自己的页表。页表的本质就是逻辑地址到物理地址的映射。

    分页存储中的逻辑地址的结构如下:

    这里写图片描述

    1)由于进程的逻辑页面大小与物理块(页帧)大小相同,故都为4K,因此需要12个位表示4K的大小(2^12=4K),即图中的【0-11】

    2)【12-31】表示的是页号。一共有20个位表示页号,也即:对于一个进程而言,一共可以有1M(2^20=1M)个页。

    3)每个进程的逻辑地址空间范围为0-2^32-1,因为:每个页大小为4K,一共有1M个页。故进程可用的逻辑空间为2^32B

    逻辑地址到物理地址的转换需要用到页表。具体细节是有一个“地址变换机构”,它有一个寄存器保存页表在内存的起始地址 以及 页表的长度。

    上面提到,一个进程最多可以有1M个页,故页表就有1M个页表项。假设每个页表项只有1B,那页表的大小也有1MB,所以:一般而言,页表也是很大的,不能全放在寄存器中,故页表也是存储在内存中的。(有些机器有“快表”,快表就是一个寄存器,它保存了页表中的部分表项);其次,也可以使用多级页表以解决单个页表太大的问题。

    那现在给定一个逻辑地址,怎么知道其物理地址呢?

    ①将【12-31】位的页号与 页表的长度比较。页号不能大于页表长度,否则越界。

    ②根据页号 找到 该页号所在的页表项,即该页号对应着哪个页表项。因为,页表项里面就存放着物理地址。

    那如何查找页表项呢?将页号乘以页表项的长度(每个页表项,其实就是一个逻辑的页 到 物理页 的映射信息),就知道了该逻辑页对应着哪个页表项(根据页号匹配页表项一般是由硬件完成的)

    然后,正如前面提到,页表也是保存在内存中的,故需要页表的内存始址(这是也为什么地址变换机构 保存 页表在内存的起始地址的原因),将页表始址 与 上面的乘积相加,就得到了该逻辑页对应的页表项的物理地址。读这个页表项的物理地址中的内容,就知道了该逻辑页对应的物理块地址(物理地址)。从而,就完成了逻辑地址到物理地址的转换。

    从上面可以看出,CPU每存取一个数据时,需要两次访问主存。一次是访问页表项的物理地址,得到了数据的物理块地址。第二次拿着物理块地址去取数据。

    在分页存储管理方式下:由于取一个数据,需要二次访存,CPU处理速度降低了一半,正由于这个原因:引入了“快表”(又称TLB(Translation Lookaside Buffer)),快表是个寄存器,用来保存那些当前访问过的页表项。从而,读页表项时,不需要再访存了,而是直接从寄存器中读取。

    虚拟存储器

    谈到虚拟存储器,总是说它从逻辑上扩充了内存的容量,why?

    内存是有限的,作业初始时保存在磁盘上的,如果要运行,必须得将相应的程序(数据)加载到内存中。那如果要运行的作业特别多,无法一下子装入内存,怎么办?

    一种方式是加内存条,这是从物理上扩充内存的容量。

    另一种方式是:先把作业的一部分程序(数据)装入内存,先让它运行着,运行过程中发现: 咦,我还需要其他的数据,而这些数据还未装入内存,因此就产生中断(缺页中断)再将数据加载到内存。

    采用这种方式,系统一次就可以将很多作业装入内存运行了。这时,从物理上看,内存还是原来的大小,但是它能运行的作业多了,因此说从逻辑上扩充了内存。

    将虚拟存储器这种思想与分页存储管理结合,一次只将作业的部分页面加载到内存中,形成了一个强大的内存分配与管理系统了。引入了虚拟存储器,同样需要有页表,记录逻辑地址到物理地址的映射,只不过此时的页表更复杂了,因为,有些页可能还在磁盘上。;还需要有缺页中断处理机构,因为毕竟只将一部分数据装入内存,会引起缺页中断嘛,就需要处理中断嘛;还需要地址变换机构,这里的地址变换机构功能更多,因为需要处理中断情况下的地址变换。

    转载自:https://www.cnblogs.com/hapjin/p/5689049.html

    展开全文
  • 存储管理——动态分区分配算法的模拟 要求设计主界面以灵活选择某算法,以下算法都要实现: a、首次适应算法 b、循环首次适应算法 c、最佳适应算法 d、最坏适应算法 e、快速适应算法 具体要求: 1)首先由...
  • java实现的一个简单的动态分区内存分配算法的实现 本人只是一个学生,写这篇东西纯粹是做完课设留个记录,代码仅供参考,不一定正确。 By Aimer_majiko_sayuri 2019-1-2 实现动态分区内存分配的...

    java实现的一个简单的动态分区内存分配算法的实现

    本人只是一个学生,写这篇东西纯粹是做完课设留个记录,代码仅供参考,不一定正确。
    																			By Aimer_majiko_sayuri	   2019-1-2
    实现动态分区内存分配的四个算法:
    1.首次适应算法。
    2.循环首次适应算法。
    3.最佳适应算法。
    4.最差适应算法。
    

    关键代码:
    //表结构
    class DynamicTable{
    int number;
    int size;
    int iniadd;
    char state;
    +各种set and get方法;
    }

    	//首次适应
    
    void allocRamFirst(int allocsize){
    		int index ,restsize,size,address,listsize;
    		listsize = dylist.size();
    		System.out.println("分配内存"+allocsize+"KB");
    		for(index = 0 ;index < listsize ;index++)
    		{
    		  DynamicTable temp = (DynamicTable) dylist.get(index);
    		  //寻找第一次适应的内存块
    		  if(temp.getState() == 'n' && temp.getSize() >= allocsize)
    			{	
    			  	address = temp.getIniadd();
    			  	size = temp.getSize();
    				restsize = 
    展开全文
  • java实现内存动态分配

    2016-07-09 08:36:20
    内存动态分配\java实现
  • Java虚拟机之内存分配详解

    千次阅读 2019-02-02 16:10:11
    java虚拟机所管理的内存中最大的一块。几乎所有的对象都是存储在堆中,并且堆是完全自动化管理的,通过垃圾回收机制,垃圾对象会被自动清理,而不需要显式的释放。 因为GC垃圾回收采用分代收集算法,因此堆空间的...
  • 采用连续分配方式之动态分区分配存储管理,使用首次适应算法、循环首次适应算法、最佳适应算法和最坏适应算法4种算法完成设计(任选两种算法)。 由用户指定申请和释放操作,结果以空闲分区表、已分配区表展示。 DEV...
  • 操作系统实验和课设,java实现动态内存分配和回收,实现算法FF,NF,WF,BF,有swing界面
  • 题目:用C语言(也可以用Java)实现采用首次适应算法内存分配和回收过程。 题目要求: 定义管理空闲分区的相关数据结构:采用空闲分区链表来管理系统中所有的空闲分区,链表中的每个节点表示一个空闲分区,登记有...
  • 实现首次适应算法内存分配函数alloc_mem(int len),其中的参数为所申请的内存空间的长度,函数返回值为所分配到的内存空间的起始地址,分配时优先将空闲区的低端部分分配出去,如果空闲区较大,则留下的高端部分仍...
  • Java在Eclipse可视化界面编写的关于操作系统的内存分配算法的课程设计。主要用来跟大家分享,互相学习。算法简单,结构清晰,适合新手参考。
  • 动态内存分配算法(详解加代码)

    千次阅读 2019-12-12 17:28:22
    动态内存分配主要有四种算法: (1) 首次适应算法:每次都从低地址开始查找,找到第一个能满足大小的空闲分区。 (2) 循环首次适应算法:首次适应算法每次要从头找,增加了查找的开销,也可能在低地 址上产生难以利用...
  • 操作系统概念课程,实验二内存分配及回收,在可变分区管理方式下,采用最先适应算法实现主存空间的分配和回收。
  • 基于java开发出具有图形界面的内存管理算法展示。...动态内存分配包括首次适应算法,最佳适应算法,最坏适应算法,循环首次适应算法;页面置换包括"Optimal", "FIFO", "LRU", "NRU", "改进Clock"等算法
  • 操作系统进程调度和内存分配算法可视化模拟,java,idea 支持的算法: 先来先服务,时间片轮转,优先级调度 首次适应,最佳适应,最坏适应
  • 本次实现均是基于顺序搜索的动态分区分配算法,为实现动态分配,通常将系统中的空闲分区链接成一个链,所谓顺序搜索是指一次搜索空闲分区链上的空闲分区,去寻找一个其大小能满足要求的分区。基于顺序搜索的动态分区...
  • Java内存管理-内存分配与回收

    千次阅读 2017-12-29 17:48:00
    Java内存管理-内存分配与回收
  • Java知识体系最强总结(2021版)

    万次阅读 多人点赞 2019-12-18 10:09:56
    本人从事Java开发已多年,平时有记录问题解决方案和总结知识点的习惯,整理了一些有关Java的知识体系,这不是最终版,会不定期的更新。也算是记录自己在从事编程工作的成长足迹,通过博客可以促进博主与阅读者的共同...
  • Java内存划分和分配

    千次阅读 2018-10-18 15:03:41
    在了解Java每个内存区域的功能之后,进一步分析Java对象如何的创建和对象的内存分配,以及如何访问对象中的内存。最后学习一下Java堆内存的分代划分和内存分配Java内存区域划分 首先通过一张图来看一下Java虚拟机...
  • 通过实现一个操作系统的内存管理的模拟系统,观察内存空闲分区管理、内存分配和回收过程,了解内存管理技术等特点,掌握内存管理中的分配、回收和置换算法,加深对请求调页系统的原理和实现过程的理解。
  • package neicunfenpei; import java.util.Scanner; public class Main { public static void main(String[] args) { ... System.out.println("请输入要分配内存还是要释放内存"); System.out.println("1
  • Java基础知识面试题(2020最新版)

    万次阅读 多人点赞 2020-02-19 12:11:27
    文章目录Java概述何为编程什么是Javajdk1.5之后的三大版本JVM、JRE和JDK的关系什么是跨平台性?原理是什么Java语言有哪些特点什么是字节码?采用字节码的最大好处是什么什么是Java程序的主类?应用程序和小程序的...
  • java写的Buddy System 内存分配算法,是applet小程序,包括分配和释放演示,没有源码。
  • 1.模拟计算机内存,按照固定地址读写 2.模拟连续分配下的循环首次适应 3.模拟连续分配下的最佳适应
  • java实现内存分配,动态优先级,时间片调度,图形化界面,界面还有点好看,嗯,
  • java虚拟机内存分配原理概述

    千次阅读 2018-08-14 18:08:16
    本文主要介绍在应用发起内存申请,到操作系统最终分配内存,采用了那些途径和方法,并比较各种方法的优劣以及使用过程中应该注意那些点。...5、堆和堆内存分配 1、应用发起请求,要求系统分配内存 (...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 183,506
精华内容 73,402
关键字:

内存分配算法java

java 订阅