老规矩,上文是本次实验的基础内容,本文实现加分项:除First Fit存储分配算法外,其他算法
NF算法的实现
NF算法(下次适应算法,Next Fit)介绍:
思想:
自上次分配空闲区域的下一个位置开始,选取第一个可满足的空闲区域
实现:
设置一个循环查找指针,开始时指向表头,每次分配从该指针处开始查找(若查到表尾则将指针置到表头)第一个遇到的可满足的区域,分配后将指针调整为所分配区域的下一个区域处。
优点:
可以减少查找空闲区域所花费的时间开销,并使空闲区域分布更均匀。
缺点:
可能分割大空闲区
代码:
#ifdef HAVE_CONFIG_H
#include <config.h>
#endif
#include <stdio.h>
#include <stdlib.h>
#define MAPSIZE 100
struct map //存储资源表结构
{
int m_addr;
int m_size;
};
struct map map[MAPSIZE]; //存储资源表
struct map* np = NULL;
//BF存储分配函数
int BF_malloc(struct map* mp, int size)
{
register int a, s;
register struct map* bp, * bpp;
for (bp = mp; bp->m_size; bp++)
{
if (bp->m_size >= size)
{
a = bp->m_addr;
s = bp->m_size;
for (bpp = bp; bpp->m_size; bpp++)
{ //最佳适应
if (bpp->m_size >= size && bpp->m_size < s)
{
a = bpp->m_addr;
s = bpp->m_size;
bp = bpp;
}
}
bp->m_addr += size;
if ((bp->m_size -= size) == 0)
do
{
bp++;
(bp - 1)->m_addr = bp->m_addr;
} while ((bp - 1)->m_size = bp->m_size);
return(a);
}
}
return(-1);
}
//WF存储分配函数
int WF_malloc(struct map* mp, int size)
{
register int a, s;
register struct map* bp, * bpp;
for (bp = mp; bp->m_size; bp++)
{
if (bp->m_size >= size)
{
a = bp->m_addr;
s = bp->m_size;
for (bpp = bp; bpp->m_size; bpp++)
{ //最坏适应
if (bpp->m_size > s)
{
a = bpp->m_addr;
s = bpp->m_size;
bp = bpp;
}
}
bp->m_addr += size;
if ((bp->m_size -= size) == 0)
do
{
bp++;
(bp - 1)->m_addr = bp->m_addr;
} while ((bp - 1)->m_size = bp->m_size);
return(a);
}
}
return(-1);
}
//NF存储分配函数
int NF_malloc(struct map* mp, int size)
{
register int a;
register struct map* bp;
if (!np || np->m_size == 0) {
np = mp;
}
bp = np;
do {
if (bp->m_size >= size)
{
a = bp->m_addr;
np = bp + 1;
bp->m_addr += size;
if ((bp->m_size -= size) == 0) {
np--;
do
{
bp++;
(bp - 1)->m_addr = bp->m_addr;
} while ((bp - 1)->m_size = bp->m_size);
}
return(a);
}
bp++;
if (bp->m_size == 0) bp = mp;
} while (bp != np);
return(-1);
}
//存储释放函数
void mfree(struct map* mp, int aa, int size)
{
register struct map* bp;
register int t;
register int a;
a = aa;
for (bp = mp; bp->m_addr <= a && bp->m_size != 0; bp++)
;//找到释放空间后面的空闲空间
if (bp > mp && (bp - 1)->m_addr + (bp - 1)->m_size == a)
{ //与前合并
(bp - 1)->m_size += size;
if (a + size == bp->m_addr)
{ //前后合并,后为空不影响
(bp - 1)->m_size += bp->m_size;
while (bp->m_size)
{//后面所有向前移动
bp++;
(bp - 1)->m_addr = bp->m_addr;
(bp - 1)->m_size = bp->m_size;
if (np && bp == np) np--;
}
}
}
else
{
if (a + size == bp->m_addr && bp->m_size)
{ //与后合并
bp->m_addr -= size;
bp->m_size += size;
}
else if (size) {
int flag = 0;
do
{ //无合并,插入新空闲区域,后面所有向后移动
t = bp->m_addr;
bp->m_addr = a;
a = t;
t = bp->m_size;
bp->m_size = size;
if (bp == np) flag = 1;
bp++;
} while (size = t);
if (np && flag) np++;
}
}
}
void init()
{
struct map* bp;
int addr, size;
int i = 0;
bp = map;
printf("Please input starting addr and total size:");
scanf("%d,%d", &addr, &size);
getchar();
bp->m_addr = addr;
bp->m_size = size;
(++bp)->m_size = 0; //表尾
}
void show_map()
{
int i = 0;
//system("clear"); //清屏
struct map* bp;
bp = map;
printf("\nCurrent memory map...\n");
printf("Address\t\tSize\n");
while (bp->m_size != 0)
{
printf("<%d\t\t%d>\n", bp->m_addr, bp->m_size);
bp++;
}
printf("\n");
}
int main()
{
int a, s;
char c;
int i;
init();
printf("please input, b for BF, w for WF,n for NF:");
scanf("%c", &c);
getchar();
do
{
show_map(); //显示存储资源表
if (np) printf("np: %d\n", np->m_addr);
printf("Please input,1 for request,2 for release,0 for exit:");
scanf("%d", &i);
getchar();
switch (i)
{
case 1:
printf("Please input size:");
scanf("%d", &s);
getchar();
if (c == 'b') //BF
a = BF_malloc(map, s);
else if (c == 'w') //WF
a = WF_malloc(map, s);
else
a = NF_malloc(map, s);
if (a == -1)
printf("request can't be satisfied\n");
else
printf("alloc memory at address:%d,size:%d\n", a, s);
break;
case 2:
printf("Please input addr and size:");
scanf("%d,%d", &a, &s);
getchar();
mfree(map, a, s);
break;
case 0:
exit(0);
}
} while (1);
}
具体实现:
struct map* np = NULL;
保存一个全局变量指针 np ,即循环查找指针,未使用时指空。
//NF存储分配函数
int NF_malloc(struct map* mp, int size)
{
register int a;
register struct map* bp;
if (!np || np->m_size == 0) {
np = mp;
}
bp = np;
do {
if (bp->m_size >= size)
{
a = bp->m_addr;
np = bp + 1;
bp->m_addr += size;
if ((bp->m_size -= size) == 0) {
np--;
do
{
bp++;
(bp - 1)->m_addr = bp->m_addr;
} while ((bp - 1)->m_size = bp->m_size);
}
return(a);
}
bp++;
if (bp->m_size == 0) bp = mp;
} while (bp != np);
return(-1);
}
1.进入 NF 后,先判断 np 是否指空或指向表位,如果是,将其重新指向表头。
2.从 np 开始,向后查找第一个足够大的空闲块,如果遍历到表尾,重新指向表头,直到再次遍历到 np 的话,返回-1。如果找到,更新该块首地址和大小,以反映内存分配,并将 np 指向下一个块。如果分配后块的大小为0,移除此块,后面的块依次向前移动,np 也向前移动。返回分配首地址a。
mfree函数的适应性调整:
//存储释放函数
void mfree(struct map* mp, int aa, int size)
{
register struct map* bp;
register int t;
register int a;
a = aa;
for (bp = mp; bp->m_addr <= a && bp->m_size != 0; bp++)
;//找到释放空间后面的空闲空间
if (bp > mp && (bp - 1)->m_addr + (bp - 1)->m_size == a)
{ //与前合并
(bp - 1)->m_size += size;
if (a + size == bp->m_addr)
{ //前后合并,后为空不影响
(bp - 1)->m_size += bp->m_size;
while (bp->m_size)
{//后面所有向前移动
bp++;
(bp - 1)->m_addr = bp->m_addr;
(bp - 1)->m_size = bp->m_size;
if (np && bp == np) np--;
}
}
}
else
{
if (a + size == bp->m_addr && bp->m_size)
{ //与后合并
bp->m_addr -= size;
bp->m_size += size;
}
else if (size) {
int flag = 0;
do
{ //无合并,插入新空闲区域,后面所有向后移动
t = bp->m_addr;
bp->m_addr = a;
a = t;
t = bp->m_size;
bp->m_size = size;
if (bp == np) flag = 1;
bp++;
} while (size = t);
if (np && flag) np++;
}
}
}
问题:
存储释放时,若前后都合并或都不合并时,后续块需要移动。此时,若 np 所指向的块被移动,需更新 np 。
具体修改:
1.若前后都合并,后续块向前移动过程中遍历到 np 所指的块,更新 np--;
2.若前后都不合并,后续块向后移动过程中,若遍历到 np 所指的块,记录,都遍历完成后,更新 np++。
运行结果:
(为了直观展示 np 指针的效果,在主函数中,show_map后,输出np->m_addr。)



分析:
由图一可以看出,申请70大小的块后,np 指向表位。且释放存储后,仍能正确指向表位;
由图二可以看出,再次申请10大小的块时,由于 np 指向表位,再次从头开始遍历。(不是BF算法);
申请5大小的块后,再次申请10大小的块,都能从正确的块中分配空间。(不是WF算法)。
由图三可以看出,当遍历到表尾时,回回到表头继续遍历。
结尾
别忘了在主函数中正确适配NF算法。
&spm=1001.2101.3001.5002&articleId=148144611&d=1&t=3&u=9027e6a0368046219e8999202eeb6ef4)
3820

被折叠的 条评论
为什么被折叠?



