最近完成了OS的课程设计,题目是模拟内存管理,实现内存块的分配与回收,在写的时候感觉这个算法挺有趣的,也找老师答辩完了,就发上来做下记录了~
模拟一个可变式分区分配的存储管理系统,首先需要确定所管理的内存容量,并对内存进行分区管理,形成空闲分区表以及已使用的内存分配表。针对内存的分配,采用了四种内存分配算法,分别是首次适应算法、循环首次适应算法、最坏适应算法、最佳适应算法
由于作业随时会调入和调出内存,在内存回收方面上,针对要回收的内存块所处的位置不同,分为四种情况,分别是要回收的内存与前一个空闲内存块相邻、要回收的内存与后一个空闲内存块相邻、要回收的内存同时与前后两个空闲内存块相邻、要回收的内存块不与任何空闲内存块相邻,根据不同情况进行编程设计
算法描述与流程
内存分配算法:
- 首次适应算法:
先将空闲分区表按照基址从小到大进行排序,当要进行分配时,对空闲分区表进行遍历,找到第一个符合要求的空闲内存块,将程序装入,装入后判断剩余空间大小是否大于阈值,如果大于阈值,则对剩余空间切割形成新的空闲内存块,并写入空闲分区表中;如果小于阈值则将剩余空间分配给装入的程序使用。
- 最坏适应算法:
算法与首次适应算法相似,唯一区别是将空闲分区表按照内存容量大小从大到小进行排序
- 最佳适应算法:
算法与首次适应算法相似,唯一区别是将空闲分区表按照内存容量大小从小到大进行排序
- 循环首次适应算法:
先将空闲分区表按照基址从小到大进行排序,首次分配时从基址最小的空闲内存块开始遍历,当找到第一个符合要求的内存块时,记录该内存快的地址,将程序装入,装入后判断剩余内存是否大于阈值,如果大于阈值,则对剩余空间切割形成新的空闲内存块,并写入空闲分区表中;如果小于阈值则分配给装入的程序使用。下次分配内存时便不再是从链首开始遍历了,而是从上一次记录的地址开始进行遍历,如果遍历到最后一个内存块还不满足要求,则继续从链首开始遍历,当找到满足要求的空闲内存块时,则再次记录地址,方便下次遍历
内存回收算法:
内存回收分为四种情况
- 要回收的内存与前一个空闲分区相邻
直接将内存回收,并对前一个空闲分区进行扩容,不用为回收的内存新增表项
- 要回收的内存与后一个空闲分区相邻
直接将内存回收,并对后一个空闲分区进行扩容,同时将基址改为被回收的内存基址,不用为回收的内存新增表项
- 要回收的内存同时与前后两个空闲分区相邻
将内存进行回收,同时对前一个空闲分区进行扩容,大小为前后两个空闲分区大小加上回收的内存,同时从空闲分区表中删去后一个空闲分区
- 要回收的内存块不与任何空闲分区相邻
直接将内存回收,并在空闲分区表中新增一项,基址为回收的内存块基址,容量也为回收的内存大小
具体代码实现
package com;
public class MemoryBlock {
private int startAddress; //内存块的起始地址(16进制表示)
private int size; //内存块大小(16进制表示)
private String id; //内存块标识符,当内存块已分配时,id为进程名称,未分配时为unused
public MemoryBlock() {
}
public MemoryBlock(int startAddress, int size, String id) {
super();
this.startAddress = startAddress;
this.size = size;
this.id = id;
}
public int getStartAddress() {
return startAddress;
}
public void setStartAddress(int startAddress) {
this.startAddress = startAddress;
}
public int getSize() {
return size;
}
public void setSize(int size) {
this.size = size;
}
public String getId() {
return id;
}
public void setId(String id) {
this.id = id;
}
@Override
public String toString() {
return "MemoryBlock [startAddress=0x" + Integer.toHexString(startAddress) + ", size=" + size &