内存分配才用的算法是首次适配算法,即低地址优先算法
新增函数
Memory.h
#ifndef __MEMORY_H__
#define __MEMORy_H__
#define EFLAGS_AC_BITS 0x00040000 //AC 在第18位
#define CR0_CACHE_DISABLE 0x60000000 //禁止缓存
#define MEMORY_MANAGER_FREES 4096 //大约是32KB
struct FREE_INFO
{
unsigned int unAddr;//空闲区 从哪开始
unsigned int unSize;//空闲区大小是多少
};
struct MEMORY_MAN
{
int nFrees;//记录空闲区数量
int nMaxFrees;//最大空闲区数量
int nLostSize;//释放失败的内存的大小总和
int nLosts; //释放失败的次数
struct FREE_INFO Free[MEMORY_MANAGER_FREES];
};
//进行内存大小的检查
unsigned int MemoryTest(unsigned int nStart, unsigned int nEnd);
unsigned int memtest_sub(unsigned int start, unsigned int end);//进行内存检测
//初始化内存管理
void MemoryManagerInit(struct MEMORY_MAN *pTemp);
//剩余内存大小的 统计
unsigned int MemoryFreeTotal(struct MEMORY_MAN *pTemp);
//空闲区的分配 返回空闲区的起始地址
unsigned int MemoryFreeMalloc(struct MEMORY_MAN *pTemp,
unsigned int unSize);
//释放内存
int MemoryManagerFree(struct MEMORY_MAN *pTemp,
unsigned int unAddress, unsigned int unSize);
#endif
汇编代码
由于gcc编译器对代码的优化,所以这段需要汇编来写,才能正确得出内存大小
每次测试 以4KB为大小 只测试最后四个字节
_memtest_sub: ; unsigned int memtest_sub(unsigned int start, unsigned int end)
PUSH EDI ; 将三个寄存器的值压入栈中
PUSH ESI
PUSH EBX
MOV ESI,0xaa55aa55 ; pat0 = 0xaa55aa55;
MOV EDI,0x55aa55aa ; pat1 = 0x55aa55aa;
MOV EAX,[ESP+12+4] ; i = start;
mts_loop:
MOV EBX,EAX
ADD EBX,0xffc ; p = i + 0xffc;
MOV EDX,[EBX] ; old = *p;
MOV [EBX],ESI ; *p = pat0;
XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff;
CMP EDI,[EBX] ; if (*p != pat1) goto fin;
JNE mts_fin
XOR DWORD [EBX],0xffffffff ; *p ^= 0xffffffff;
CMP ESI,[EBX] ; if (*p != pat0) goto fin;
JNE mts_fin
MOV [EBX],EDX ; *p = old;
ADD EAX,0x1000 ; i += 0x1000;
CMP EAX,[ESP+12+8] ; if (i <= end) goto mts_loop;
JBE mts_loop
POP EBX
POP ESI
POP EDI
RET
mts_fin:
MOV [EBX],EDX ; *p = old;
POP EBX
POP ESI
POP EDI
RET
Memory.c
//进行内存测试 看CPU的型号 得出内存大小
unsigned int MemoryTest(unsigned int nStart, unsigned int nEnd)
{
char Flag486 = 0;
unsigned int Eflag, CR0, MemorySize = 0;
Eflag = io_load_eflags();//读入Eflag寄存器
Eflag |= EFLAGS_AC_BITS;//设置AC位等于1
io_store_eflags(Eflag);//写回Eflag
Eflag = io_load_eflags();//386就算是设置了 也还是0
if(0 != (Eflag & EFLAGS_AC_BITS))
{
Flag486 = 1;//证明是486以上的CPU
}
Eflag &= ~EFLAGS_AC_BITS;
io_store_eflags(Eflag);
if (0 != Flag486)
{
CR0 = load_cr0();
CR0 |= CR0_CACHE_DISABLE;//禁止缓存
store_cr0(CR0);
}
MemorySize = memtest_sub(nStart, nEnd);
if(0 != Flag486)
{
CR0 = load_cr0();
CR0 &= ~CR0_CACHE_DISABLE;//允许缓存
store_cr0(CR0);
}
return MemorySize;
}
//初始化内存管理
void MemoryManagerInit(struct MEMORY_MAN *pTemp)
{
pTemp->nFrees = 0;//可用信息的数目
pTemp->nLosts = 0;//内存释放失败的次数
pTemp->nLostSize = 0; //释放失败的总内存数
pTemp->nMaxFrees = 0; //用于观察可用状态 free的最大值
return;
}
//剩余内存大小的 统计
unsigned int MemoryFreeTotal(struct MEMORY_MAN *pTemp)
{
unsigned int i;
unsigned int unTotal = 0;
for(i = 0; i < pTemp->nFrees; i++)
{
unTotal += pTemp->Free[i].unSize;
}
return unTotal;
}
//空闲区的分配 返回空闲区的起始地址
unsigned int MemoryFreeMalloc(struct MEMORY_MAN *pTemp,
unsigned int unSize)
{
unsigned int i;
unsigned int Address;
for ( i = 0; i < pTemp->nFrees; i++)//在空闲区中找
{
if(pTemp->Free[i].unSize >= unSize)//如果可以放下
{
Address = pTemp->Free[i].unAddr;//记录空闲区的起始地址
pTemp->Free[i].unAddr += unSize;//进行内存的分配
pTemp->Free[i].unSize -= unSize;
if(0 == pTemp->Free[i].unSize)//即该空闲区 刚好可以放下
{
pTemp->nFrees--;
for(; i < pTemp->nFrees; i++)
{
pTemp->Free[i] = pTemp->Free[i+1];
}
}
return Address;//返回起始地址
}
}
//没找到 返回0
return 0;
}
//释放内存
int MemoryManagerFree(struct MEMORY_MAN *pTemp,
unsigned int unAddress, unsigned int unSize)
{
int i, j;
for(i = 0; i < pTemp->nFrees; i++)
{
if(unAddress < pTemp->Free[i].unAddr)
{
break; //找到第一个 起始地址 大于他的空闲区
}
}
//如果说 找到的这个起始地址 前面 还有空闲区 看是否 可以合并
if(i > 0)
{
//可以和前面的合并
if(unAddress == (pTemp->Free[i-1].unAddr +
pTemp->Free[i-1].unSize))
{
//合并
pTemp->Free[i-1].unSize += unSize;
//看后面 是否还有空闲区 看是否可以合并
if(i < pTemp->nFrees)
{
//可以合并
if((unAddress + unSize) == pTemp->Free[i].unAddr )
{
//合并
pTemp->Free[i-1].unSize +=
pTemp->Free[i].unSize;
//合并后 空闲区-1
pTemp->nFrees--;
for(; i < pTemp->nFrees; i++)
{
pTemp->Free[i] = pTemp->Free[i+1];
}
}
}
return 0;//成功释放
}
}
//不能与前面的 可用空间合并到 一起
if(i < pTemp->nFrees)
{
//可以和 后边的合并
if((unAddress + unSize) == pTemp->Free[i].unAddr)
{
pTemp->Free[i].unAddr = unAddress;
pTemp->Free[i].unSize += unSize;
return 0;
}
}
//既不能和前面的合并 又不能和后边的 合并
//而且 没有超过 最大空闲区 数量
if(pTemp->nFrees < MEMORY_MANAGER_FREES)
{
//往后边挪动 一个单位
for(j = pTemp->nFrees; j > i; j--)
{
pTemp->Free[j] = pTemp->Free[j-1];
}
pTemp->nFrees++;
//更新最大值
pTemp->nMaxFrees = (pTemp->nMaxFrees) > (pTemp->nFrees) ?
(pTemp->nMaxFrees) : (pTemp->nFrees);
pTemp->Free[i].unAddr = unAddress;
pTemp->Free[i].unSize = unSize;
return 0;
}
//不能释放
pTemp->nLosts++;
pTemp->nLostSize += unSize;
return -1;
}
main.c
//获取内存大小
MemorySize = MemoryTest(0x00400000, 0xbfffffff);
//初始化内存管理器
MemoryManagerInit(MenMan);
//设定空闲区
MemoryManagerFree(MenMan, 0x00001000, 0x0009e000);
MemoryManagerFree(MenMan, 0x00400000, MemorySize-0x00400000);