09_挑战内存管理

内存分配才用的算法是首次适配算法,即低地址优先算法

新增函数

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);
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值