lwip內存分配詳解對比 mem_init memp_init 源碼分析

Lwip內存分配

mem_init ()分配方式介紹

內存堆的初始化函數,主要是告知內存堆的起止地址,以及初始化空閒列表,mem_malloc( )  申請分配內存。將總共須要的字節數做爲參數傳遞給該函數,返回值是指向最新分配的內存的指針,而若是內存沒有分配好,則返回值是 NULL。內存的分配和釋放,不能在中斷函數裏面進行。內存堆是全局變量,所以內存的申請、釋放操做作了線程安全保護,若是有多個線程在同時進行內存申請和釋放,那麼可能會由於信號量的等待而致使申請耗時較長。mem_free()釋放空間到內存堆中。c#

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()分配策略:分配類型大小固定的內存區,分配的個數是能夠用戶配置的,用戶應該根據協議棧實際使用情況this

進行配置。把協議棧中全部內存區放在一片連續的內存區域,這就是一個大的緩衝池。簡單說就是先開闢一堆各類類型的內存區放那,要用時直接取就好了。spa

memp_num:組用於保存各類類型緩衝池的成員數目操作系統

memp_sizes:組用於保存各類類型緩衝池的結構大小.net

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)
相關文章
相關標籤/搜索