嵌入式–内存池
直接上代码,自己体会。嵌入式设备,一般keil提供的堆很小,一般都不使用。使用内存池,自己可以调节内存大小。
头文件 malloc.h
#ifndef __MALLOC_H
#define __MALLOC_H
#include <stdint.h>
#ifndef NULL
#define NULL (0)
#endif
//内存参数设定.
#define MEM_BLOCK_SIZE 32 //内存块大小为32字节
#define MEM_MAX_SIZE 1*1024 //最大管理内存
#define MEM_ALLOC_TABLE_SIZE MEM_MAX_SIZE/MEM_BLOCK_SIZE //内存表大小
//内存管理控制器
struct _m_mallco_dev
{
void (*init)(void); //初始化
uint8_t (*perused)(void); //内存使用率
uint8_t *membase; //内存池
uint16_t *memmap; //内存管理状态表
uint8_t memrdy; //内存管理是否就绪
};
extern struct _m_mallco_dev mallco_dev; //在mallco.c里面定义
void mymemset(void *s, uint8_t c, uint32_t count); //设置内存
void mymemcpy(void *des, void *src, uint32_t n); //复制内存
void mem_init(void); //内存管理初始化函数(外/内部调用)
uint32_t mem_malloc(uint32_t size); //内存分配(内部调用)
uint8_t mem_free(uint32_t offset); //内存释放(内部调用)
uint8_t mem_perused(void); //得内存使用率(外/内部调用)
//用户调用函数
void myfree(void *ptr); //内存释放(外部调用)
void *mymalloc(uint32_t size); //内存分配(外部调用)
void *myrealloc(void *ptr, uint32_t size); //重新分配内存(外部调用)
#endif
源文件 malloc.c
#include "malloc.h"
//内存池(4字节对齐)
__align(4) uint8_t membase[MEM_MAX_SIZE]; //SRAM内存池
//内存管理表
uint16_t memmapbase[MEM_ALLOC_TABLE_SIZE]; //SRAM内存池MAP
//内存管理参数
const uint32_t memtblsize=MEM_ALLOC_TABLE_SIZE; //内存表大小
const uint32_t memblksize=MEM_BLOCK_SIZE; //内存分块大小
const uint32_t memsize=MEM_MAX_SIZE; //内存总大小
//内存管理控制器
struct _m_mallco_dev mallco_dev=
{
mem_init, //内存初始化
mem_perused, //内存使用率
membase, //内存池
memmapbase, //内存管理状态表
0, //内存管理未就绪
};
//复制内存
//*des:目的地址
//*src:源地址
//n:需要复制的内存长度(字节为单位)
void mymemcpy(void *des,void *src, uint32_t n)
{
uint8_t *xdes=des;
uint8_t *xsrc=src;
while(n--)*xdes++=*xsrc++;
}
//设置内存
//*s:内存首地址
//c :要设置的值
//count:需要设置的内存大小(字节为单位)
void mymemset(void *s, uint8_t c, uint32_t count)
{
uint8_t *xs = s;
while(count--)*xs++=c;
}
//内存管理初始化
void mem_init(void)
{
//内存状态表数据清零
mymemset(mallco_dev.memmap, 0,memtblsize*2);
//内存池所有数据清零
mymemset(mallco_dev.membase, 0,memsize);
//内存管理初始化OK
mallco_dev.memrdy=1;
}
//获取内存使用率
//返回值:使用率(0~100)
uint8_t mem_perused(void)
{
uint32_t used=0;
uint32_t i;
for(i=0; i<memtblsize; i++)
{
if(mallco_dev.memmap[i])used++;
}
return (used*100)/(memtblsize);
}
//内存分配(内部调用)
//memx:所属内存块
//size:要分配的内存大小(字节)
//返回值:0XFFFFFFFF,代表错误;其他,内存偏移地址
uint32_t mem_malloc(uint32_t size)
{
signed long offset=0;
uint16_t nmemb; //需要的内存块数
uint16_t cmemb=0;//连续空内存块数
uint32_t 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;
}
//找到了连续nmemb个空内存块
if(cmemb==nmemb)
{
//标注内存块非空
for(i=0; i<nmemb; i++)
{
mallco_dev.memmap[offset+i]=nmemb;
}
//返回偏移地址
return (offset*memblksize);
}
}
//未找到符合分配条件的内存块
return 0XFFFFFFFF;
}
//释放内存(内部调用)
//offset:内存地址偏移
//返回值:0,释放成功;1,释放失败;
uint8_t mem_free(uint32_t 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;
}
}
//释放内存(外部调用)
//ptr:内存首地址
void myfree(void *ptr)
{
uint32_t offset;
if(ptr==NULL)
{
return;//地址为0.
}
offset=(uint32_t)ptr-(uint32_t)mallco_dev.membase;
mem_free(offset);
}
//分配内存(外部调用)
//size:内存大小(字节)
//返回值:分配到的内存首地址.
void *mymalloc(uint32_t size)
{
uint32_t offset;
offset=mem_malloc(size);
if(offset==0XFFFFFFFF)return NULL;
else return (void*)((uint32_t)mallco_dev.membase+offset);
}
//重新分配内存(外部调用)
//*ptr:旧内存首地址
//size:要分配的内存大小(字节)
//返回值:新分配到的内存首地址.
void *myrealloc(void *ptr,uint32_t size)
{
uint32_t offset;
offset = mem_malloc(size);
if(offset==0XFFFFFFFF)
{
return NULL;
}
else
{
//拷贝旧内存内容到新内存
mymemcpy((void*)((uint32_t)mallco_dev.membase+offset),ptr,size);
//释放旧内存
myfree(ptr);
//返回新内存首地址
return (void*)((uint32_t)mallco_dev.membase+offset);
}
}