🔥码云GVP开源项目 12k star Uniapp+ElementUI 功能强大 支持多语言、二开方便! 广告
在学习内存堆之前,我们先看看内存堆的的组织结构,它包括了内存数据结构与某些重要的全局变量,具体见代码清单 5-9。 ``` 1 struct mem 2 { 3 /** index (-> ram[next]) of the next struct */ 4 mem_size_t next; (1) 5 /** index (-> ram[prev]) of the previous struct */ 6 mem_size_t prev; (2) 7 /** 1: this area is used; 0: this area is unused */ 8 u8_t used; (3) 9 #if MEM_OVERFLOW_CHECK 10 /** this keeps track of the user allocation size for guard checks */ 11 mem_size_t user_size; 12 #endif 13 }; 14 15 #define MIN_SIZE 12 (4) 16 17 LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED+(2U*SIZEOF_STRUCT_MEM)); (5) 18 19 #define LWIP_RAM_HEAP_POINTER ram_heap (6) 20 21 22 /** pointer to the heap (ram_heap): 23 for alignment, ram is now a pointer instead of an array */ 24 static u8_t *ram; (7) 25 26 /** the last entry, always unused! */ 27 static struct mem *ram_end; (8) 28 29 #if !NO_SYS 30 static sys_mutex_t mem_mutex; (9) 31 #endif 32 33 static struct mem * LWIP_MEM_LFREE_VOLATILE lfree; (10) ``` * (1)(2):可能很多人都会认为next与prev是一个指针,分别指向下一个内存块与上一个内存块,但是其实这两个字段表示的是目的地址的偏移量,基地址是整个内存堆的起始地址。 * (3):used字段用于标记该内存是否已经被使用。 * (4):申请的内存最小为12字节,因为一个内存块最起码需要保持mem结构体的信息,以便于对内存块进行操作,而该结构体在对齐后的内存大小就是12字节。 * (5):内存堆的大小是由这个宏定义的,该语句在编译器处理之后就是u8_t ram_heap[(((MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM)) + MEM_ALIGNMENT - 1U))];,其中MEM_SIZE_ALIGNED宏是内存堆大小MEM_SIZE经过内存对齐后的大小;而SIZEOF_STRUCT_MEM则是结构体mem经过内存对其后的大小,MEM_ALIGNMENT则是CPU按多少字节对其的宏定义,一般为4。 * (6):ram_heap[]就是内核的内存堆空间,LWIP_RAM_HEAP_POINTER这个宏定义相对于重新命名ram_heap。 * (7):ram是一个全局指针变量,指向内存堆对齐后的起始地址,因为真正的内存堆起始地址不一定是按照CPU的对齐方式对齐的,而此处就要确保内存堆的起始地址是对齐的。 * (8):mem类型指针,指向内存堆中最后一个内存块。 * (9):互斥量,用户保护内存堆的互斥量,暂时未用。 * (10):mem类型指针,指向内存堆中低地址的空闲内存块,简单来说就是空闲内存块链表指针。