內存分配是在預先設定的未使用內存堆中分配出需求的空間,然後將該空間起始地址返回給調用者,操作系統內核有一套自己的數據結構描述、記錄哪些空間範圍已經被分配、哪些未使用,不同操作系統有不同的內存分配策略。
一種內存堆分配方法(摘自《嵌入式網絡那些事》):
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;
}