操作系统内存动态分区分配算法(Java实现)

一. 内存的作用

内存是计算机的一个重要组成部分,它的主要作用在于配合 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 [email protected]
 */
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("------------------------------------");
    }
}

猜你喜欢

转载自blog.csdn.net/baidu_32045201/article/details/79048758