Lwip内存分配
mem_init ()分配方式介绍
内存堆的初始化函数,主要是告知内存堆的起止地址,以及初始化空闲列表,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_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)