1 概述

本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是:

  • BF
  • NF
  • WF
  • FF

分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解。

2 四种分配方式

2.1 概念

操作系统中有一个动态分区分配的概念,内存在初始化的时候不会划分区域,而是在进程装入的时候,根据所要装入的进程动态地对内存空间进行划分,以提高内存空间的利用率,降低碎片的大小,主要的方法有一下四种:

  • 首次适应算法(First Fit):从空闲分区链首开始查找,直到找到一个满足其大小要求的空闲分区为止
  • 循环首次适应算法(Next Fit):从上次找到的空闲分区的下一个开始查找
  • 最佳适应算法(Best Fit):把空闲分区按大小递增的方式形成分区链,找到第一个能满足要求的空闲分区就进行分配
  • 最坏适应算法(Worst Fit):与最佳适应算法相反,把空闲分区按大小递减的方式形成分区链,找到第一个能满足要求的空闲分区就进行分配

2.2 例子

假设现在有100MB的内存空间,某一时刻先后分配了20MB4MB10MB内存,示意图如下:

现在需要再分配5MB内存。

若采用FF,因为FF是直接按顺序分配内存,从低地址开始搜索空闲分区,因此便会从第一块空闲分区分配5MB(地址0-5),示意图:

若采用NFNFFF类似,只不过NF是从上一次找到的空闲分区的下一块开始查找,因为上一次分配的是10MB,因此会从最后一块空闲分区(地址80-100)分配内存:

若采用BFBF是遍历所有空闲分区并找到一个能满足要求的最小分区,也就会找到一个比5MB大的空闲分区,且该空闲分区是所有空闲分区中最小的,也就是地址为64-70的空闲分区:

若采用WFWFBF相反,总是从最大的空闲分区开始分配,因此会从地址为30-60的空闲分区进行分配:

3 代码实现

3.1 总览

代码分成了四个类:

  • Main:测试
  • Print:输出打印
  • Table:表示每一个分区
  • TableList:对分区进行控制,包括初始化,分配,回收等

3.2 Main

Main是测试类,代码如下:

public class Main {private final static TableList list = new TableList(64);public static void main(String[] args) {list.useWF();
//        list.useBF();
//        list.useNF();
//        list.useFF();list.allocate(10);list.allocate(20);list.free(10);list.show();list.allocate(8);list.show();list.allocate(13);list.allocate(1);list.show();list.free(1);list.allocate(9);list.free(13);list.show();list.allocate(18);list.show();list.allocate(3);list.allocate(4);list.free(20);list.free(8);list.show();list.allocate(8);list.free(9);list.show();list.clear();list.show();}
}

通过TableList对内存进行分配以及释放,初始化分配64MB大小内存,切换分配算法时使用前四行的其中一行即可。

3.3 Table

Table类表示每一个分区,无论是空闲的还是已分配的,成员变量有四个,分别是:

  • 起始地址
  • 大小
  • 是否空闲(只有两种状态,空闲或分配)
  • 是否是上一次分配(NF专用)

代码如下:

@AllArgsConstructor
public class Table {@Getter@Setterprivate int address;@Setter@Getterprivate int size;private boolean free;@Getter@Setterprivate boolean lastAllocated;public static Table freeTable(int address,int size){return new Table(address,size,true,false);}public static Table allocatedTable(int address,int size){return new Table(address,size,false,false);}public boolean isFree(){return free;}public boolean isAllocated(){return !isFree();}public void setFree(){free = true;}
}

只有一些GetterSetter,为了方便提供了一个创建空闲分区或已分配分区的静态方法,指定起始地址和大小即可。

3.4 TableList

TableList是整个算法的核心类,成员变量如下:

private final List<Table> list = new ArrayList<>();
private final int totalSize;
private boolean ff = false;
private boolean nf = false;
private boolean bf = false;
private boolean wf = false;
private boolean first = true;
private final static Print print = new Print();

list就是所有的空闲分区与已分配分区组成的数组,totalSize是总大小,接着是四个控制算法的布尔变量,first表示是否是第一次分配内存,因为第一次的话四种算法都是固定的从地址为0处开始分配。

接下来就是内存分配算法以及释放算法。

3.4.1 FF

if (ff)
{for (int i = 0; i < list.size(); i++) {Table table = list.get(i);if(table.isFree() && table.getSize() >= size){int address = table.getAddress();Table allocated = Table.allocatedTable(address,size);table.setAddress(address+size);table.setSize(table.getSize()-size);list.add(i,allocated);return;}}
}

FF的实现还是比较简单的,直接遍历列表,如果是空闲分区并满足大小要求,直接进行分配,修改空闲分区的起始地址和大小并插入一个新的已分配分区到列表中即可。

3.4.2 NF

else if (nf)
{int lastNFIndex = findLastAllocated();int i = lastNFIndex;do{if(i == list.size())i = 0;Table table = list.get(i);if(table.isFree() && table.getSize() >= size){int address = table.getAddress();Table allocated = Table.allocatedTable(address,size);table.setAddress(address+size);table.setSize(table.getSize()-size);list.get(lastNFIndex).setLastAllocated(false);table.setLastAllocated(true);list.add(i,allocated);return;}++i;}while (i != lastNFIndex);
}

NF的话需要提前记录上一次分配的位置,通过Table中的lastAllocated确定上一次分配的位置,找到后从该位置开始遍历列表,注意需要进行绕回处理,因为到末尾位置后有可能还没有能满足的空闲分区,此时需要将下标绕回到0并再次遍历直到到达上一次分配的位置。

3.4.3 BF+WF

由于BFWF都需要遍历所有的空闲分区,只是前者是选择最小满足要求的,后者是选择最大满足要求的,因此两者的实现差别在于一个判断大小的符号,代码如下:

else
{int i;int target = -1;for (i = 0; i < list.size(); i++) {Table table = list.get(i);if(table.isFree()){if(table.getSize() >= size){if(target == -1)target = i;else{if(bf){if(list.get(target).getSize() > table.getSize())target = i;}else{if(list.get(target).getSize() < table.getSize())target = i;}}}}}if(target != -1){Table table = list.get(target);int address = table.getAddress();table.setAddress(address+size);table.setSize(table.getSize()-size);list.add(target,Table.allocatedTable(address,size));return;}
}

首先遍历找到符合条件的空闲分区的下标,接着通过判断target,也就是目标空闲分区的下标,如果为-1表示没有找到符合条件的空闲分区,如果不为-1直接分配空间。

3.4.4 释放算法

释放算法的设计是比较复杂的,代码如下:

public void free(int size)
{int index = 0;while(index < list.size()){if(list.get(index).isAllocated() && list.get(index).getSize() == size)break;++index;}if(index >= list.size()){print.freeFailed(size);return;}int address = list.get(index).getAddress();if(index == 0){list.get(0).setFree();if(index+1 < list.size()){Table nextTable = list.get(index+1);if(nextTable.isFree()){list.get(0).setSize(nextTable.getSize()+size);list.remove(index+1);}}}else if(index == list.size()-1){list.get(index).setFree();Table lastTable = list.get(index-1);if(lastTable.isFree()){lastTable.setSize(lastTable.getSize()+size);list.remove(index);}}else{Table before = list.get(index-1);Table after = list.get(index+1);if(before.isFree() && after.isFree()){before.setSize(before.getSize()+size+after.getSize());list.remove(index+1);list.remove(index);}else if(before.isFree() && after.isAllocated()){before.setSize(before.getSize()+size);list.remove(index);}else if(before.isAllocated() && after.isFree()){after.setSize(after.getSize()+size);after.setAddress(address);list.remove(index);}else{list.get(index).setFree();}}
}

主要考虑了六种情况(黄色代表需要释放的空间,橙色是已分配的内存空间):

  • 第一种情况就是需要释放首部的分区,此时需要修改后面空闲分区的起始地址和大小,并删除目标分区
  • 第二种情况是释放尾部的分区,此时需要修改前面空闲分区的大小即可,无需修改起始地址,并删除目标分区
  • 第三种情况是后面是已分配的分区,前面的空闲分区,需要修改前面空闲分区的大小,并删除目标分区
  • 第四种情况是前面是已分配的分区,后面是空闲分区,需要修改后面的空闲分区的起始地址以及大小,并删除目标分区
  • 第五种情况是前后都是已分配的分区,此时只需要修改目标分区的标志为空闲即可,无需额外操作
  • 第六种情况是前后都是空闲分区,这种情况下需要进行连接操作,具体来说就是先修改前面空闲分区的大小,接着删除目标分区以及后面的空闲分区

下面回到代码,首先是判断第一种情况:

if(index == 0)
{list.get(0).setFree();if(index+1 < list.size()){Table nextTable = list.get(index+1);if(nextTable.isFree()){list.get(0).setSize(nextTable.getSize()+size);list.remove(index+1);}}
}

也就是需要释放首部的分区,通过setFree()设置标志位表示空闲状态,接着判断是否需要修改后面空闲分区的大小,因为有可能后面是一个已分配的分区而不是空闲分区。

else if(index == list.size()-1)
{list.get(index).setFree();Table lastTable = list.get(index-1);if(lastTable.isFree()){lastTable.setSize(lastTable.getSize()+size);list.remove(index);}
}

这里是判断第二种情况,也就是释放尾部的分区,同样需要判断前一个分区是已分配的分区还是空闲的分区,是空闲分区的话修改大小并移除目标分区。

else
{Table before = list.get(index-1);Table after = list.get(index+1);if(before.isFree() && after.isFree()){before.setSize(before.getSize()+size+after.getSize());list.remove(index+1);list.remove(index);}else if(before.isFree() && after.isAllocated()){before.setSize(before.getSize()+size);list.remove(index);}else if(before.isAllocated() && after.isFree()){after.setSize(after.getSize()+size);after.setAddress(address);list.remove(index);}else{list.get(index).setFree();}
}

接下来是最后四种情况的判断,首先获取前一个以及后一个分区,接着按上面算法的思路进行判断即可。

4 测试

WF为例,默认大小64MB,测试顺序如下:

  • 分配10MB
  • 分配20MB
  • 释放10MB
  • 打印结果
  • 分配8MB
  • 打印结果
  • 分配13MB
  • 分配1MB
  • 打印结果
  • 释放1MB
  • 分配9MB
  • 释放13MB
  • 打印结果
  • 分配18MB
  • 打印结果
  • 分配3MB
  • 分配4MB
  • 释放20MB
  • 释放8MB
  • 打印结果
  • 分配8MB
  • 释放9MB
  • 打印结果
  • 清空
  • 打印结果

输出:

Free           :      0-10MB
Allocated      :      10-30MB
Free           :      30-64MB----------------------------------------------------------------Free           :      0-10MB
Allocated      :      10-30MB
Allocated      :      30-38MB
Free           :      38-64MB----------------------------------------------------------------Free           :      0-10MB
Allocated      :      10-30MB
Allocated      :      30-38MB
Allocated      :      38-51MB
Allocated      :      51-52MB
Free           :      52-64MB----------------------------------------------------------------Free           :      0-10MB
Allocated      :      10-30MB
Allocated      :      30-38MB
Free           :      38-51MB
Allocated      :      51-60MB
Free           :      60-64MB----------------------------------------------------------------Do nothing.
Allocated failed, out of memory
Free           :      0-10MB
Allocated      :      10-30MB
Allocated      :      30-38MB
Free           :      38-51MB
Allocated      :      51-60MB
Free           :      60-64MB----------------------------------------------------------------Allocated      :      0-4MB
Free           :      4-38MB
Allocated      :      38-41MB
Free           :      41-51MB
Allocated      :      51-60MB
Free           :      60-64MB----------------------------------------------------------------Allocated      :      0-4MB
Allocated      :      4-12MB
Free           :      12-38MB
Allocated      :      38-41MB
Free           :      41-64MB----------------------------------------------------------------Free           :      0-64MB----------------------------------------------------------------

读者可以自行画图验证。

5 源码

  • Github
  • 码云
  • GitCode

Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF相关推荐

  1. 各种存储分配算法java代码实现_Java实现操作系统中四种动态内存分配算法:BF+NF+WF+FF...

    1 概述 本文是利用Java实现操作系统中的四种动态内存分配方式 ,分别是:BF NF WF FF 分两部分,第一部分是介绍四种分配方式的概念以及例子,第二部分是代码实现以及讲解. 2 四种分配方式 ...

  2. java遍历list_Java中四种遍历List的方法总结(推荐)

    实例如下: package com.ietree.basic.collection.loop; import java.util.ArrayList; import java.util.Iterato ...

  3. C++ 高级数据类型(四)—— 动态内存分配

    到目前为止,我们的程序中我们只用了声明变量.数组和其他对象(objects)所必需的内存空间,这些内存空间的大小都在程序执行之前就已经确定了.但如果我们需要内存大小为一个变量,其数值只有在程序运行时 ...

  4. 操作系统-动态内存分配算法

    内存分配算法 1.首次适应算法(FF) 2.循环首次适应算法(NF) 3.最佳适应算法(BF) 4.最坏适应算法(WF) 本程序使用前端技术实现(html+css+JavaScript) 新建以下文件 ...

  5. java动态分区分配_操作系统动态分区分配算法课程设计java版解析.doc

    湖 南 文 理 学 院 实 验 报 告 课程名称 操作系统课程设计 实验名称 存储管理--动态分区分配算法的模拟 成绩 学生姓名 曹乐 专业 计算机 班级.学号 13101 18 同组者姓名 实验日期 ...

  6. java动态分区分配算法,操作系统_动态分区分配算法课程设计_java版

    <操作系统_动态分区分配算法课程设计_java版>由会员分享,可在线阅读,更多相关<操作系统_动态分区分配算法课程设计_java版(13页珍藏版)>请在人人文库网上搜索. 1. ...

  7. java动态分区分配_操作系统 动态分区分配算法课程设计 java版.pdf

    操作系统 动态分区分配算法课程设计 java版 湖 南 文 理 学 院 实 验 报 告 课程名称 操作系统课程设计 实验名称 存储管理--动态分区分配算法的模拟 成绩 学生姓名 曹乐 专业 计算机 班 ...

  8. postgresql源码学习(57)—— pg中的四种动态库加载方法

    一. 基础知识 1. 什么是库 库其实就是一些通用代码,可以在程序中重复使用,比如一些数学函数,可以不需要自己编写,直接调用相关函数即可实现,避免重复造轮子. 在linux中,支持两种类型的库: 1. ...

  9. 操作系统实验2—实现动态分区分配模拟程序

    操作系统实验2-实现动态分区分配模拟程序 文章目录 操作系统实验2-实现动态分区分配模拟程序 实验描述 设计思路 上机代码 测试结果 心得体会 实验描述 实验内容: 编写一个可变分区存储管理程序,模拟 ...

最新文章

  1. 屏蔽storm ui的kill功能
  2. C#面向对象(四)虚方法实现多态
  3. 为什么wait和notify只能在synchronized中?
  4. VRRP+SmartLink双上行配置案例
  5. anaconda安装后只有几个文件,大量文件缺失,开始栏里没有图标的解决方法
  6. php代码丑,php – 屏幕截图你生命中见过的最丑陋的HTML
  7. mongodb副本集修改配置问题
  8. php 递归函数 示例,php 递归函数用法示例
  9. 计算机显示10的负次方,我输入10的9次方在EXCEL里,为什么总变成日期了?怎么办/excel10的负次方怎么打...
  10. 号外:中国雅虎相册即将关闭原图下载 请网友及时备份
  11. 实现从一个按钮跳转到另一个页面
  12. Channel 通道详解
  13. 27. 尚融宝申请借款额度
  14. /proc/cpuinfo 文件详解
  15. jmeter安装成功后打不开,提示:Cause: CannotResolveClassException: com.blazemeter.jmeter.threads.concurrency.Conc
  16. ReentrantLock源码走读分析
  17. 【学术】可以分享一下关于“社会计算”有哪些国内外顶级会议吗?
  18. 无线网dhcp服务器租期,缺省情况下,DHCP服务器分配IP地址的租期为()。
  19. oracle一个表空间超出32g,Oracle表空间超出32G的解决方法
  20. 30个优秀的开源CMS建站系统,采用PHP开发

热门文章

  1. 《DistilBERT, a distilled version of BERT: smaller, faster, cheaper and lighter》(NeurIPS-2019)论文阅读
  2. 如何关闭 WPS 的高级打印功能
  3. 基于python中selenium库,实现百度账号的自动登陆
  4. 减少使用非 SDK 接口,提升系统稳定性
  5. zip文件的由来以及zip文件格式规范
  6. 苹果ios手机游戏开发
  7. 查看Python文档的几种方法
  8. 中国乳房X射线探测器市场趋势报告、技术动态创新及市场预测
  9. 51单片机——7段数码管的循环显示
  10. “CL.exe”已退出,代码为 -1073741515。