预备知识
(1) 首次拟合 从表头指针查找,找到的第一个大小不小于m的结点的一部分分配给用户。
分配时需要查找可利用空间表,回收时直接插到表头即可。
(2) 最佳拟合 将可利用空间表中一个不小于m且最接近m的空闲块的一部分分配给用户,推荐按结点从小到大排序,回收时把释放的空闲块插入到合适的位置上。
最佳拟合法适用于请求分配的内存大小范围较广的系统。
最佳拟合无论分配回收都需要查找可利用空间表,因此最费时间。
(3) 最差拟合 将可利用空间表中不小于n且是链表中最大的空闲块的一部分分配给用户,此时结点应当从大到小排序,分配时只需从链表中删除第一个结点,并分配一部分给用户,剩余部分插入到合适位置。
最差拟合每次从最大结点分配,最终结点大小趋于一致,适用于内存大小范围较窄的系统。
最差拟合分配时直接表头分配,回收时需要把空闲块插入在合适位置上,因此需要查找链表。
边界标识法
边界标识法是操作系统中用以动态分区分配的一种存储管理方法,系统将所有空闲块连接在一个双重循环链表结构的可利用空间表中。
边界标识法结点结构
每个内存区头部和底部设标识,标识该区域是占用块(1)还是空闲块(0),使得在回收用户释放的空闲块时易于判别在物理位置上与其相邻的内存内存区域是否为空闲块,以便合并空闲存储区。
//space指示存储单元,单元大小由head中的size域表示,以head和foot作为边界,head和foot中都有标志域tag
typedef struct WORD
{
union
{ //head和foot分别是节点的的第一个字和最后一个字
WORD *llink; //头部域,指向前驱结点
WORD *uplink; //底部域,指向本节点头部,大小随size改变
};
int tag; //0空闲1占用,后部和尾部均有
int size;
WORD *rlink; //头部域,指向后继结点
OtherType other; //字的其他部分
} WORD, head, foot, *Space; //*Space可利用空间指针类型
#define FootLoc(p) p + p->size - 1
指向p所指结点的底部
首次拟合法分配
找到表头指针所指结点起在可利用空间表中查找,找到第一个容量不小于请求分配的存储量的空闲块就进行分配
(1)如果待分配块容量为m个字,每次分配分配n个字给用户,剩余m-n大小的结点仍然留在链表中(剩余容量极小的块)
解决方法:设定一个e,m-n<e时,就将m整块分配给用户,反之分配高地址的n个字给用户(避免修改指针)
(2)如果每次分配都从表头指针开始找的话,会使得存储量小的结点密集在头指针附近,所以每次查找应当从不同结点开始查找,实现方法是使头指针指向刚分配过结点的后继结点
#define e 40
Space AllocBoundTag(Space &pav, int n)
{
//若有不小于n的空闲块则分配相应的存储块,返回首地址;
//若分配后表不空,则pav指向表中刚分配过的结点的后继结点
WORD *p = NULL,*f=NULL;
for (p = pav; p->size < n && p->rlink != pav; p = p->rlink)
; // p->rlink!=pav,循环链表的头
if (!p || p->size < n)
return NULL;