LwIP之动态内存堆
生活随笔
收集整理的这篇文章主要介绍了
LwIP之动态内存堆
小编觉得挺不错的,现在分享给大家,帮大家做个参考.
内存堆其实就是一个数组。为了方便管理需要将内存堆首尾组织成内存块,因此多分配的2 * SIZEOF_STRUCT_MEM大小的空间
/* 内存堆空间 */ static u8_t ram_heap[MEM_SIZE_ALIGNED + (2 * SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];动态内存堆会被组织成内存块,用于管理内存的分配和释放
/* 内存块结构体 */ struct mem {/* 指向后一个内存块 */mem_size_t next;/* 指向前一个内存块 */mem_size_t prev;/* 内存块是否被使用 1:被使用 0:未使用 */u8_t used; };
初始化堆内存,将对内部组织成内存块链表。
/* 内存堆初始化 */ void mem_init(void) {struct mem *mem;/* 内存堆地址 */ram = LWIP_MEM_ALIGN(ram_heap);/* 将内存堆首部组织成一个内存块,该内存块包含整个内存堆有效区域 */mem = (struct mem *)ram;mem->next = MEM_SIZE_ALIGNED;mem->prev = 0;mem->used = 0;/* 在内存堆尾部组织成一个内存块 */ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED];ram_end->used = 1;ram_end->next = MEM_SIZE_ALIGNED;ram_end->prev = MEM_SIZE_ALIGNED;/* 更新地址最低的空闲内存块 */lfree = (struct mem *)ram; }
内存分配,从链表中找到一个合适的内存块,分配给程序。将剩下的内存组织成新的内存块,并挂接到链表。
/* 申请内存 */ void *mem_malloc(mem_size_t size) {mem_size_t ptr, ptr2;struct mem *mem, *mem2;/* 内存申请不能为0 */if (size == 0) {return NULL;}/* 申请大小字节对齐 */size = LWIP_MEM_ALIGN_SIZE(size);/* 申请大小最小12字节 */if(size < MIN_SIZE_ALIGNED) {size = MIN_SIZE_ALIGNED;}/* 内存申请不能超过内存堆 */if (size > MEM_SIZE_ALIGNED) {return NULL;}/* 遍历所有内存块 */for (ptr = (u8_t *)lfree - ram; ptr < MEM_SIZE_ALIGNED - size; ptr = ((struct mem *)&ram[ptr])->next) {/* 内存块地址 */mem = (struct mem *)&ram[ptr];/* 找出合适的内存块 */if ((!mem->used) && (mem->next - (ptr + SIZEOF_STRUCT_MEM)) >= size) {/* 内存块过大 */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;}} else {/* 当前内存块标记为已使用 */mem->used = 1;}/* 当前内存块为地址最低的空闲内存块 */if (mem == lfree) {/* 更新地址最低的空闲内存块 */while (lfree->used && lfree != ram_end) {lfree = (struct mem *)&ram[lfree->next];}}/* 返回内存地址 */return (u8_t *)mem + SIZEOF_STRUCT_MEM;}}return NULL; }
释放内存,将内存重新组织成内存块插入链表。相邻内存堆都空闲,需要合并。
/* 释放内存 */ void mem_free(void *rmem) {struct mem *mem;if (rmem == NULL) {return;}/* 内存地址必须在内存堆中 */if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {return;}/* 通过内存地址找出内存块结构体指针 */mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);/* 将内存块标识为空闲 */mem->used = 0;/* 更新地址最低空闲块 */if (mem < lfree) {lfree = mem;}/* 合并空闲块 */plug_holes(mem); } /* 合并空闲块 */ static void plug_holes(struct mem *mem) {struct mem *nmem;struct mem *pmem;/* 下一个内存块 */nmem = (struct mem *)&ram[mem->next];/* 下一个内存块未被使用,并且不是最后一个内存块 */if (mem != nmem && nmem->used == 0 && (u8_t *)nmem != (u8_t *)ram_end) {/* 更新地址最低的空闲内存块 */if (lfree == nmem) {lfree = mem;}/* 和后一个内存块合并 */mem->next = nmem->next;((struct mem *)&ram[nmem->next])->prev = (u8_t *)mem - ram;}/* 上一个空闲块 */pmem = (struct mem *)&ram[mem->prev];/* 上一个内存块未使用 */if (pmem != mem && pmem->used == 0) {/* 更新地址最低的空闲内存块 */if (lfree == mem) {lfree = pmem;}/* 和上一个内存块合并 */pmem->next = mem->next;((struct mem *)&ram[mem->next])->prev = (u8_t *)pmem - ram;} }
除了基本的分配和释放,协议栈还mem_realloc函数和mem_calloc函数
mem_realloc函数,能够收缩内存,将原有的内存缩小。缩小的部分重新组织成内存块,挂接到链表。
/* 收缩内存 */ void *mem_realloc(void *rmem, mem_size_t newsize) {mem_size_t size;mem_size_t ptr, ptr2;struct mem *mem, *mem2;/* 新内存大小字节对齐 */newsize = LWIP_MEM_ALIGN_SIZE(newsize);/* 内存大小最小12字节 */if(newsize < MIN_SIZE_ALIGNED) {newsize = MIN_SIZE_ALIGNED;}/* 内存大小不能超过内存堆 */if (newsize > MEM_SIZE_ALIGNED) {return NULL;}/* 内存地址必须在内存堆中 */if ((u8_t *)rmem < (u8_t *)ram || (u8_t *)rmem >= (u8_t *)ram_end) {return rmem;}/* 通过内存地址找出内存块结构体指针 */mem = (struct mem *)((u8_t *)rmem - SIZEOF_STRUCT_MEM);/* 内存在内存堆中的偏移量 */ptr = (u8_t *)mem - ram;/* 计算内存块内存大小 */size = mem->next - ptr - SIZEOF_STRUCT_MEM;/* 只能缩小,不能扩展 */if (newsize > size) {return NULL;}/* 内存大小不变,直接返回 */if (newsize == size) {return rmem;}/* 下一个内存块空闲 */mem2 = (struct mem *)&ram[mem->next];if(mem2->used == 0) {mem_size_t next;/* 将切割下来的内存和下一个内存块合并 */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;}} /* 下一个内存块不空闲 */else if (newsize + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED <= size) {/* 将切割下来的内存重新组织成内存块 */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;}}/* 返回内存指针 */return rmem; }mem_calloc函数,申请内存的同时,将内存清空。
/* 申请内存并清零 */ 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; }
总结
以上是生活随笔为你收集整理的LwIP之动态内存堆的全部内容,希望文章能够帮你解决所遇到的问题。
- 上一篇: 区块链将如何影响你的生活?链圈大佬、美图
- 下一篇: 我30岁了。现在开始编程,会不会太晚?