内存堆的初始化函数,主要是告知内存堆的起止地址,以及初始化空闲列表,mem_malloc( ) 申请分配内存。将总共需要的字节数作为参数传递给该函数,返回值是指向最新分配的内存的指针,而如果内存没有分配好,则返回值是 NULL。内存的分配和释放,不能在中断函数里面进行。内存堆是全局变量,因此内存的申请、释放操作做了线程安全保护,如果有多个线程在同时进行内存申请和释放,那么可能会因为信号量的等待而导致申请耗时较长。mem_free()释放空间到内存堆中。
mem_init()分配策略:事先定义好大小的内存块中进行管理,其内存分配的策略是采用最快合适(First Fit)方式,只要找到一个比所请求的内存大的空闲块,就从中切割出合适的块,并把剩余的部分返回到动态内存堆中。分配的内存块有个最小大小的限制,要求请求的分配大小不能小于 MIN_SIZE,否则请求会被分配到 MIN_SIZE 大小的内存空间。
内存释放的过程是相反的过程,但分配器会查看该节点前后相邻的内存块是否空闲,如果空闲则合并成一个大的内存空闲块。
优点:就是内存浪费小,比较简单,适合用于小内存的管理。缺点:就是如果频繁的动态分配和释放,可能会造成严重的内存碎片,如果在碎片情况严重的话,可能会导致内存分配不成功。
void mem_init(void) { struct mem *mem; //检查对齐 LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM & (MEM_ALIGNMENT-1)) == 0); /* align the heap 堆栈对齐*/ ram = LWIP_MEM_ALIGN(ram_heap); /* initialize the start of the heap */ mem = (struct mem *)ram; mem->next = MEM_SIZE_ALIGNED; //下一块指向这块的末尾 //#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) 就是内存大小 顺便对齐 mem->prev = 0; mem->used = 0; /* initialize the end of the heap */ ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; //&(ram+1600)即末尾 ram_end->used = 1; //用了一块内存 ram_end->next = MEM_SIZE_ALIGNED; ram_end->prev = MEM_SIZE_ALIGNED; mem_sem = sys_sem_new(1); //无操作系统define 1 /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)ram; MEM_STATS_AVAIL(avail, MEM_SIZE_ALIGNED); //mem_stats 内存状态 }
// 没有使用 MEM_USE_POOLS 时mem定义 struct mem { /** index (-> ram[next]) of the next struct */ mem_size_t next; /** index (-> ram[next]) of the next struct */ mem_size_t prev; /** 1: this area is used; 0: this area is unused */ u8_t used; };
MEM_STATS_AVAIL(x,y)
#if MEM_STATS //0 #define MEM_STATS_AVAIL(x, y) lwip_stats.mem.x = y #else #define MEM_STATS_AVAIL(x, y)
memp_init()分配策略:分配类型大小固定的内存区,分配的个数是可以用户配置的,用户应该根据协议栈实际使用状况
进行配置。把协议栈中所有内存区放在一片连续的内存区域,这就是一个大的缓冲池。简单说就是先开辟一堆各种类型的内存区放那,要用时直接取就行了。
memp_num:组用于保存各种类型缓冲池的成员数目
memp_sizes:组用于保存各种类型缓冲池的结构大小
memp_tab:指针数组用于指向各种类型缓冲池当前空闲节点
memp_init():内存池的初始化,主要是为每种内存池建立链表 memp_tab,其链表是逆序的,此外,如果有统计功能使能的话,也把记录了各种内存池的数目。
memp_malloc():如果相应的 memp_tab 链表还有空闲的节点,则从中切出一个节点返回,否则返回空。
memp_free():把释放的节点添加到相应的链表 memp_tab 头上
优点:实现简单,内存的分配、释放效率高,可以有效防止内存碎片的产生。缺点:是会浪费部分内存。
void memp_init(void) { struct memp *memp; //下面介绍 u16_t i, j; for (i = 0; i < MEMP_MAX; ++i) { MEMP_STATS_AVAIL(used, i, 0); MEMP_STATS_AVAIL(max, i, 0); MEMP_STATS_AVAIL(err, i, 0); MEMP_STATS_AVAIL(avail, i, memp_num[i]); } memp = LWIP_MEM_ALIGN(memp_memory); //memp_memory见http://my.oschina.net/u/274829/blog/271361 /* for every pool: */ for (i = 0; i < MEMP_MAX; ++i) { memp_tab[i] = NULL; /* create a linked list of memp elements */ for (j = 0; j < memp_num[i]; ++j) { memp->next = memp_tab[i]; //memp_tab[]相当于 tmp缓存 memp_tab[i] = memp; memp = (struct memp *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i] #if MEMP_OVERFLOW_CHECK + MEMP_SANITY_REGION_AFTER_ALIGNED #endif ); } } #if MEMP_OVERFLOW_CHECK //溢出检查 memp_overflow_init(); //没用 /* check everything a first time to see if it worked */ memp_overflow_check_all(); #endif /* MEMP_OVERFLOW_CHECK */ }
struct memp
struct memp { struct memp *next; //下一个链表 #if MEMP_OVERFLOW_CHECK const char *file; int line; #endif /* MEMP_OVERFLOW_CHECK */ };
MEMP_STATS_AVAIL
#if MEMP_STATS //0 #define MEMP_STATS_AVAIL(x, i, y) lwip_stats.memp[i].x = y #else #define MEMP_STATS_AVAIL(x, i, y)