lwip内存分配详解对比 mem_init memp_init 源码分析

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)


你可能感兴趣的:(源码分析,memp_init,lwip内存分配详解对比,mem_init)