内存分配是在预先设定的未使用内存堆中分配出需求的空间,然后将该空间起始地址返回给调用者,操作系统内核有一套自己的数据结构描述、记录哪些空间范围已经被分配、哪些未使用,不同操作系统有不同的内存分配策略。
一种内存堆分配方法(摘自《嵌入式网络那些事》):
void *mem_malloc(mem_size_t size)
{
mem_size_t ptr, ptr2; //局部变量,保存内存块起始地址偏移量
struct mem *mem, *mem2;
if(size == 0){
return NULL;
}
size = LWIP_MEM_ALIGN_SIZE(size); //将size修正为内存对齐字节数的整数倍
if(size < MIN_SIZE_ALIGNED){
size = MIN_SIZE_ALIGNED;
}
if(size > MEN_SIZE_ALIGNED){
return NULL;
}
//从lfree开始遍历,找出第一个长度大于size的空闲内存块
for(ptr = (u8_t*)lfree-ram; ptr < MEM_SIZE_ALIGNED-size;
ptr = ((struct mem*)&ram[ptr])->next)
{
mem = (struct mem*)&ram[ptr];
//若该内存块未使用,且其空间不小于(用户请求大小+系统结构体mem)
if((!mem->used)&&(mem->next-(ptr+SIZEOF_STRUCT_MEM)) >= size){
//接下来判断是将该内存块全部分配给用户,还是截取其中的一部分,判断标准是:
//若做截取,判断剩下的部分是否能组成一个最小的内存块,即是否能剩下
//SIZEOF_STRUCT_MEM+MIN_SIZE_ALIGNED的大小
if(mem->next-(ptr+SIZEOF_STRUCT_MEM) >=
(size+SIZEOF_STRUCT_MEM+MIN_SIZE_ALIGNED)){
//需截取
ptr2 = ptr+SIZEOF_STRUCT_MEM+size; //分配后剩余空间起始处偏移量
mem2 = (struct mem*)&ram[ptr2];
mem2->used = 0;
mem2->next = mem->next; //将空闲块插入到原空闲内存块链表中
mem2->prev = ptr;
mem->next = ptr2;
mem->used = 1;
if(mem2->next != MEM_SIZE_ALIGNED){
((struct mem*)&ram[mem2->next])->prev = ptr2;
}
MEM_STATS_INC_USED(used, (size+SIZEOF_STRUCT_MEM));//增加全变量
}else {//直接分配,不用截取
mem->used = 1;
MEM_STATS_INC_USED(used, mem->next-((u8_t*)mem-ram));//增加全变量
}
//分配完毕
if(mem == lfree){ //lfree指向的内存块被分配出去时,更新lfree
while(lfree->used&&lfree != ram_end){
lfree = (struct mem*)&ram[lfree->next];
}
}
return (u8_t*)mem + SIZEOF_STRUCT_MEM; //分配成功,返回可用内存块起始区域
}//此内存块不满足要求,下一个for循环
}//所有内存块都不满足要求
return NULL;
}