LwIP之动态内存堆
生活随笔
收集整理的這篇文章主要介紹了
LwIP之动态内存堆
小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.
?
內(nèi)存堆其實(shí)就是一個(gè)數(shù)組。為了方便管理需要將內(nèi)存堆首尾組織成內(nèi)存塊,因此多分配的2?* SIZEOF_STRUCT_MEM大小的空間
/* 內(nèi)存堆空間 */ static u8_t ram_heap[MEM_SIZE_ALIGNED + (2 * SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];動(dòng)態(tài)內(nèi)存堆會(huì)被組織成內(nèi)存塊,用于管理內(nèi)存的分配和釋放
/* 內(nèi)存塊結(jié)構(gòu)體 */ struct mem {/* 指向后一個(gè)內(nèi)存塊 */mem_size_t next;/* 指向前一個(gè)內(nèi)存塊 */mem_size_t prev;/* 內(nèi)存塊是否被使用 1:被使用 0:未使用 */u8_t used; };?
初始化堆內(nèi)存,將對(duì)內(nèi)部組織成內(nèi)存塊鏈表。
/* 內(nèi)存堆初始化 */ void mem_init(void) {struct mem *mem;/* 內(nèi)存堆地址 */ram = LWIP_MEM_ALIGN(ram_heap);/* 將內(nèi)存堆首部組織成一個(gè)內(nèi)存塊,該內(nèi)存塊包含整個(gè)內(nèi)存堆有效區(qū)域 */mem = (struct mem *)ram;mem->next = MEM_SIZE_ALIGNED;mem->prev = 0;mem->used = 0;/* 在內(nèi)存堆尾部組織成一個(gè)內(nèi)存塊 */ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];ram_end->used = 1;ram_end->next = MEM_SIZE_ALIGNED;ram_end->prev = MEM_SIZE_ALIGNED;/* 更新地址最低的空閑內(nèi)存塊 */lfree = (struct mem *)ram; }?
內(nèi)存分配,從鏈表中找到一個(gè)合適的內(nèi)存塊,分配給程序。將剩下的內(nèi)存組織成新的內(nèi)存塊,并掛接到鏈表。
/* 申請(qǐng)內(nèi)存 */ void *mem_malloc(mem_size_t size) {mem_size_t ptr, ptr2;struct mem *mem, *mem2;/* 內(nèi)存申請(qǐng)不能為0 */if (size == 0) {return NULL;}/* 申請(qǐng)大小字節(jié)對(duì)齊 */size = LWIP_MEM_ALIGN_SIZE(size);/* 申請(qǐng)大小最小12字節(jié) */if(size < MIN_SIZE_ALIGNED) {size = MIN_SIZE_ALIGNED;}/* 內(nèi)存申請(qǐng)不能超過內(nèi)存堆 */if (size > MEM_SIZE_ALIGNED) {return NULL;}/* 遍歷所有內(nèi)存塊 */for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; ptr = ((struct mem *)&ram[ptr])->next) {/* 內(nèi)存塊地址 */mem = (struct mem *)&ram[ptr];/* 找出合適的內(nèi)存塊 */if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {/* 內(nèi)存塊過大 */if (mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)) {/* 將多出來的內(nèi)存重新組織成內(nèi)存塊 */ptr2 = ptr + SIZEOF_STRUCT_MEM + size;mem2 = (struct mem *)&ram[ptr2];mem2->used = 0;mem2->next = mem->next;mem2->prev = ptr;/* 當(dāng)前內(nèi)存塊標(biāo)記為已使用,并將新內(nèi)存塊插入鏈表 */mem->next = ptr2;mem->used = 1;if (mem2->next != MEM_SIZE_ALIGNED) {((struct mem *)&ram[mem2->next])->prev = ptr2;}} else {/* 當(dāng)前內(nèi)存塊標(biāo)記為已使用 */mem->used = 1;}/* 當(dāng)前內(nèi)存塊為地址最低的空閑內(nèi)存塊 */if (mem == lfree) {/* 更新地址最低的空閑內(nèi)存塊 */while (lfree->used && lfree != ram_end) {lfree = (struct mem *)&ram[lfree->next];}}/* 返回內(nèi)存地址 */return (u8_t *)mem + SIZEOF_STRUCT_MEM;}}return NULL; }?
釋放內(nèi)存,將內(nèi)存重新組織成內(nèi)存塊插入鏈表。相鄰內(nèi)存堆都空閑,需要合并。
/* 釋放內(nèi)存 */ void mem_free(void *rmem) {struct mem *mem;if (rmem == NULL) {return;}/* 內(nèi)存地址必須在內(nèi)存堆中 */if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {return;}/* 通過內(nèi)存地址找出內(nèi)存塊結(jié)構(gòu)體指針 */mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);/* 將內(nèi)存塊標(biāo)識(shí)為空閑 */mem->used = 0;/* 更新地址最低空閑塊 */if (mem < lfree) {lfree = mem;}/* 合并空閑塊 */plug_holes(mem); } /* 合并空閑塊 */ static void plug_holes(struct mem *mem) {struct mem *nmem;struct mem *pmem;/* 下一個(gè)內(nèi)存塊 */nmem = (struct mem *)&ram[mem->next];/* 下一個(gè)內(nèi)存塊未被使用,并且不是最后一個(gè)內(nèi)存塊 */if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {/* 更新地址最低的空閑內(nèi)存塊 */if (lfree == nmem) {lfree = mem;}/* 和后一個(gè)內(nèi)存塊合并 */mem->next = nmem->next;((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;}/* 上一個(gè)空閑塊 */pmem = (struct mem *)&ram[mem->prev];/* 上一個(gè)內(nèi)存塊未使用 */if (pmem != mem && pmem->used == 0) {/* 更新地址最低的空閑內(nèi)存塊 */if (lfree == mem) {lfree = pmem;}/* 和上一個(gè)內(nèi)存塊合并 */pmem->next = mem->next;((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;} }?
除了基本的分配和釋放,協(xié)議棧還mem_realloc函數(shù)和mem_calloc函數(shù)
mem_realloc函數(shù),能夠收縮內(nèi)存,將原有的內(nèi)存縮小。縮小的部分重新組織成內(nèi)存塊,掛接到鏈表。
/* 收縮內(nèi)存 */ void *mem_realloc(void *rmem, mem_size_t newsize) {mem_size_t size;mem_size_t ptr, ptr2;struct mem *mem, *mem2;/* 新內(nèi)存大小字節(jié)對(duì)齊 */newsize = LWIP_MEM_ALIGN_SIZE(newsize);/* 內(nèi)存大小最小12字節(jié) */if(newsize < MIN_SIZE_ALIGNED) {newsize = MIN_SIZE_ALIGNED;}/* 內(nèi)存大小不能超過內(nèi)存堆 */if (newsize > MEM_SIZE_ALIGNED) {return NULL;}/* 內(nèi)存地址必須在內(nèi)存堆中 */if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {return rmem;}/* 通過內(nèi)存地址找出內(nèi)存塊結(jié)構(gòu)體指針 */mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);/* 內(nèi)存在內(nèi)存堆中的偏移量 */ptr = (u8_t *)mem - ram;/* 計(jì)算內(nèi)存塊內(nèi)存大小 */size = mem->next - ptr - SIZEOF_STRUCT_MEM;/* 只能縮小,不能擴(kuò)展 */if (newsize > size) {return NULL;}/* 內(nèi)存大小不變,直接返回 */if (newsize == size) {return rmem;}/* 下一個(gè)內(nèi)存塊空閑 */mem2 = (struct mem *)&ram[mem->next];if(mem2->used == 0) {mem_size_t next;/* 將切割下來的內(nèi)存和下一個(gè)內(nèi)存塊合并 */next = mem2->next;ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;if (lfree == mem2) {lfree = (struct mem *)&ram[ptr2];}mem2 = (struct mem *)&ram[ptr2];mem2->used = 0;mem2->next = next;mem2->prev = ptr;mem->next = ptr2;if (mem2->next != MEM_SIZE_ALIGNED) {((struct mem *)&ram[mem2->next])->prev = ptr2;}} /* 下一個(gè)內(nèi)存塊不空閑 */else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {/* 將切割下來的內(nèi)存重新組織成內(nèi)存塊 */ptr2 = ptr + SIZEOF_STRUCT_MEM + newsize;mem2 = (struct mem *)&ram[ptr2];if (mem2 < lfree) {lfree = mem2;}mem2->used = 0;mem2->next = mem->next;mem2->prev = ptr;mem->next = ptr2;if (mem2->next != MEM_SIZE_ALIGNED) {((struct mem *)&ram[mem2->next])->prev = ptr2;}}/* 返回內(nèi)存指針 */return rmem; }mem_calloc函數(shù),申請(qǐng)內(nèi)存的同時(shí),將內(nèi)存清空。
/* 申請(qǐng)內(nèi)存并清零 */ void *mem_calloc(mem_size_t count, mem_size_t size) {void *p;p = mem_malloc(count * size);if (p) {memset(p, 0, count * size);}return p; }?
總結(jié)
以上是生活随笔為你收集整理的LwIP之动态内存堆的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 区块链将如何影响你的生活?链圈大佬、美图
- 下一篇: 我30岁了。现在开始编程,会不会太晚?