内存管理也就是堆区的管理,不管是BSS还是栈区那些都由系统分配以及管理的,所以内存管理主要实现malloc以及free等函数,在代码运行时,分配和释放内存。
#define BLOCK_SIZE 32 //内存块32字节
#define MAX_SIZE 1024 //堆区分配1K字节
#define TABLE_SIZE MAX_SIZE/BLOCK_SIZE //分配表大小
struct _m_mallco_dev //内存管理控制器
{
void (*init)(u8); //初始化的函数指针
u8 (*perused)(u8); //查看内存使用率的函数指针
u8 *membase; //堆区地址
u16 *memmap; //堆区分配表地址
u8 memrdy; //堆区状态 0 未初始化 1 初始化
};
1,程序运行前,就要先开辟好堆区空间,这个空间是定死的即运行后就不能更改。
__align(4) u8 base[MAX_SIZE];//4字节对齐
2,程序运行前,就要先开辟好堆区空间的映射空间,也就是堆区的分配表,但与文件分配表不同,如堆区每32字节就分为一个块,堆区的每一个块和分配表的每一个值对应,形成映射关系,分配表记录着每个块分配的长度。
u16 mapbase[TABLE_SIZE];
3,程序运行前,还要准备好管理这个堆区以及分配表的控制变量,需要先知道存储堆区大小,堆区分块大小,分配表大小,以及需要一个内存管理控制器。
const u32 memtblsize=TABLE_SIZE;
const u32 memblksize=BLOCK_SIZE;
const u32 memsize=MAX_SIZE;
struct _m_mallco_dev mallco_dev=
{
mem_init, //编写好的初始化函数
mem_perused,//编写好的内存使用率函数
membase, //堆区基地址
memmapbase, //分配表基地址
0, //初始化状态为0
};
4, 编写工具函数
void mymemcpy(//内存拷贝函数
void *des, //拷贝的目标地址
void *src, //拷贝的源地址
u32 n ) //拷贝数量
{
u8 *xdes=des;
u8 *xsrc=src;
while(n--)*xdes++=*xsrc++;
}
void mymemset(//内存设置函数
void *s, //内存地址
u8 c, //需要设置的值
u32 count) //设置的数量
{
u8 *xs = s;
while(count--)*xs++=c;
}
5,初始化堆区
void mem_init() //初始化堆区
{
mymemset(mallco_dev.memmap, 0,memtblsize); //分配表空间置0
mymemset(mallco_dev.membase, 0,memsize);//堆区空间置0
mallco_dev.memrdy=1;//内存状态置为1,初始化完成
}
u8 mem_perused() //获得内存使用率函数
{ //遍历分配表,计算非0的个数,得到块个数/总块个数
u32 used=0;
u32 i;
for(i=0;i<memtblsize;i++)
{
if(mallco_dev.memmap[i])used++;
}
return (used*100)/(memtblsize);
}
5,实现malloc
//外部调用函数
void *mymalloc(//开辟size长度空间,返回堆区基地址+偏移地址
u32 size)
{
u32 offset;
offset=mem_malloc(size);
if(offset==0XFFFFFFFF)return NULL;
else return (void*)((u32)mallco_dev.membase+offset);
}
//内部调用函数
u32 mem_malloc(//开辟size长度空间,返回偏移地址
u32 size)
{
signed long offset=0;
u16 nmemb;
u16 cmemb=0;
u32 i;
if(!mallco_dev.memrdy)mallco_dev.init();//如果没有初始化先初始化
if(size==0)return 0XFFFFFFFF;
nmemb=size/memblksize; //计算需要分配的块个数
if(size%memblksize)nmemb++; //计算需要分配的块个数
for(offset=memtblsize-1;offset>=0;offset--)//循环遍历内存表
{
if(!mallco_dev.memmap[offset])cmemb++;//发现空块
else cmemb=0;
if(cmemb==nmemb)//找到需要的空闲空间
{
for(i=0;i<nmemb;i++)
{
mallco_dev.memmap[offset+i]=nmemb;
//对应的分配表置为块的个数
}
return (offset*memblksize); //返回偏移地址
}
}
return 0XFFFFFFFF;
}
6,实现free
//外部函数
void myfree(void *ptr)
{
u32 offset;
if(ptr==NULL)return;
offset=(u32)ptr-(u32)mallco_dev.membase; //偏移地址
mem_free(offset);
}
//内部函数
u8 mem_free(u32 offset) //偏移地址
{
int i;
if(!mallco_dev.memrdy)
{
mallco_dev.init();
return 1;
}
if(offset<memsize)//没有溢出的地址
{
int index=offset/memblksize;//首地址所在的块
int nmemb=mallco_dev.memmap[index]; //首地址所在块开辟的长度
for(i=0;i<nmemb;i++)
{
mallco_dev.memmap[index+i]=0; //分配表清空
}
return 0;
}else return 2;
}