LWIP再探----內存池管理

這這裏是接上一篇內存池管理部分的,這裏若是讀者一打開memp.c的話會感受特別那一理解原做者在幹嗎,可是看懂了就明白原做者是怎麼巧妙的使用了宏。廢話很少說先說了下我分析是一下宏的條件是數組

前提條件
MEMP_STATS = 0
MEMP_OVERFLOW_CHECK = 0數據結構

首先要去簡單的看下#include "lwip/priv/memp_std.h"文件的格式,只須要明白這個文件依賴LWIP_MEMPOOL(name,num,size,desc)這個宏,而且在文件結尾將宏清除。函數

所以出現底下的最難的兩塊學習

#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) #include "lwip/priv/memp_std.h"

const struct memp_desc *const memp_pools[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, #include "lwip/priv/memp_std.h" };

先說第一個,繼續追LWIP_MEMPOOL_DECLARE的定義以下,看完繼續懵逼中。。。,可是不能慌一個個宏替換出來spa

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ \ LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ \ static struct memp *memp_tab_ ## name; \ \ const struct memp_desc memp_ ## name = { \ DECLARE_LWIP_MEMPOOL_DESC(desc) \ LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ LWIP_MEM_ALIGN_SIZE(size), \ (num), \ memp_memory_ ## name ## _base, \ &memp_tab_ ## name \ };

裏面相關宏的實現彙總以下設計

#ifndef LWIP_DECLARE_MEMORY_ALIGNED #define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)]     
#endif

#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name)      

#define DECLARE_LWIP_MEMPOOL_DESC(desc)

#define LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(name)

#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U))

最後就有這樣一個過程指針

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ LWIP_DECLARE_MEMORY_ALIGNED(memp_memory_ ## name ## _base, ((num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))); \ \ LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(memp_stats_ ## name) \ \ static struct memp *memp_tab_ ## name; \ \ const struct memp_desc memp_ ## name = { \ DECLARE_LWIP_MEMPOOL_DESC(desc) \ LWIP_MEMPOOL_DECLARE_STATS_REFERENCE(memp_stats_ ## name) \ LWIP_MEM_ALIGN_SIZE(size), \ (num), \ memp_memory_ ## name ## _base, \ &memp_tab_ ## name \ }; |
    | \|/
   
#define LWIP_MEMPOOL_DECLARE(name,num,size,desc) \ memp_memory_RAW_PCB_base[(num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \ static struct memp *memp_tab_RAW_PCB; \ const struct memp_desc memp_RAW_PCB = {\ LWIP_MEM_ALIGN_SIZE(size), \ (num), \ memp_memory_RAW_PCB _base,\ &memp_tab_ RAW_PCB\ };

而後就是這樣子的宏替換,此處未所有列舉code

#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc) #include "lwip/priv/memp_std.h"
    |
    | \|/ memp_memory_RAW_PCB_base[(num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \ static struct memp *memp_tab_RAW_PCB; const struct memp_desc memp_RAW_PCB = { 「RAW_PCB」 LWIP_MEM_ALIGN_SIZE(size), (num), memp_memory_RAW_PCB _base, &memp_tab_ RAW_PCB }; memp_memory_UDP_PCB_base[(num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size)))]; \ static struct memp *memp_tab_UDP_PCB; const struct memp_desc memp_UDP_PCB = { 「UDP_PCB」 LWIP_MEM_ALIGN_SIZE(size), (num), memp_memory_UDP_PCB _base, &memp_tab_UDP_PCB }; . . .

,同理理解到這裏下面繼續第二個宏就是同理結果以下orm

const struct memp_desc *const memp_pools[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name, #include "lwip/priv/memp_std.h" }; |
    | \|/

const struct memp_desc *const memp_pools[MEMP_MAX] = { &memp_RAW_PCB, &memp_UDP_PCB, . . . }

注意這裏的MEMP_MAX是這樣來的blog

typedef enum { #define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, #include "lwip/priv/memp_std.h" MEMP_MAX } memp_t; |
| \|/ typedef enum { MEMP_RAW_PCB, MEMP_UDP_PCB, . . . MEMP_MAX } memp_t;

而後這裏還還須要瞭解一個結構體的定義以下,

struct memp_desc { #if defined(LWIP_DEBUG) || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY
  /** Textual description */
  const char *desc; #endif /* LWIP_DEBUG || MEMP_OVERFLOW_CHECK || LWIP_STATS_DISPLAY */
  /** Element size */ u16_t size; #if !MEMP_MEM_MALLOC
  /** Number of elements */ u16_t num; /** Base address */ u8_t *base; /** First free element of each pool. Elements form a linked list. */
  struct memp **tab; #endif /* MEMP_MEM_MALLOC */ };

這樣memp_pools就將整個mempool的內存串到了一個結構體數組中。要注意此時每一個memp_pools中的memp_desc結構體中的memp_tab_UDP_PCB還只是一個指針的指針,並未有具體的實際意義。而後memp_init會進行這一工做,去掉宏不編譯的部分
memp_init以下

void memp_init(void) { u16_t i; /* for every pool: */
  for (i = 0; i < LWIP_ARRAYSIZE(memp_pools); i++) { memp_init_pool(memp_pools[i]); } }

就是循環調用memp_init_pool,接着看去掉宏簡化後的memp_init_pool

void memp_init_pool(const struct memp_desc *desc) { int i; struct memp *memp; *desc->tab = NULL; memp = (struct memp *)LWIP_MEM_ALIGN(desc->base); /* create a linked list of memp elements */
  for (i = 0; i < desc->num; ++i) { memp->next = *desc->tab; *desc->tab = memp; memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size } }

到這裏全部內存池的定義和初始化已經完成了借用野火的一張圖,初始化後的pool結構以下

每個類型的池最後由,tab將全部的空閒池串起來,組成一個內存池單向鏈表。到此最難理解的部分已經完了,接下來內存池的內存分配和釋放就是很簡單的內容了。

內存申請

void * memp_malloc(memp_t type){ void *memp; // 取對應內存池的控制塊
  memp = do_memp_malloc_pool(memp_pools[type]); return memp; } //這個函數內部實際上調用了 do_memp_malloc_pool簡化後以下, static void * do_memp_malloc_pool(const struct memp_desc *desc) { struct memp *memp; SYS_ARCH_DECL_PROTECT(old_level); SYS_ARCH_PROTECT(old_level); memp = *desc->tab; if (memp != NULL) { *desc->tab = memp->next; SYS_ARCH_UNPROTECT(old_level); /* cast through u8_t* to get rid of alignment warnings */
    return ((u8_t *)memp + MEMP_SIZE); } else { SYS_ARCH_UNPROTECT(old_level); } return NULL; }

由於tab是空閒pool的頭,因此內存申請直接就是返回tab指向pool就能夠了。同時內存釋放就是將pool重新插入單向鏈表的操做了。具體簡化的代碼以下

內存釋放

void memp_free(memp_t type, void *mem) { if (mem == NULL) { return; } do_memp_free_pool(memp_pools[type], mem); } //調用do_memp_free_pool static void do_memp_free_pool(const struct memp_desc *desc, void *mem) { struct memp *memp; SYS_ARCH_DECL_PROTECT(old_level); /* cast through void* to get rid of alignment warnings */ memp = (struct memp *)(void *)((u8_t *)mem - MEMP_SIZE); SYS_ARCH_PROTECT(old_level); memp->next = *desc->tab; *desc->tab = memp; SYS_ARCH_UNPROTECT(old_level); }

如今LWIP的兩種內存策略的實現方式,都已經理解過了,其中內存池的溢出檢測部分沒有說,可是已經能夠幫助咱們使用LWIP了,做者設計兩種內存策略是有他的設計初衷的,看了#include "lwip/priv/memp_std.h"文件就知道,內存池的出現就是爲一些特殊的長度固定的數據結構設計的,他分配快速,釋放亦是,而且很定不會有內存碎片,可是這仍是一種空間換時間的作法,由於內存池申請函數,支持若是當前尺寸的pool用完了,能夠分配更大的池。內存堆就是用來應對大小不定的內存分配場合的,當人LWIP支持用堆實現pool也支持用pool實現堆,同時還支持用戶池,這些功能均可以經過宏簡單 的配置具體以下

MEM_LIBC_MALLOC  使用C庫

MEMP_MEM_MALLOC  使用內存堆替換內襯池。

MEM_USE_POOLS  使用內存池替換內存堆

MEMP_USE_CUSTOM_POOLS   使用用戶定義的內存池,這個實現須要用戶提供一個文件lwippools.h,並按以下形式定義字節的內存池,要求內存池的大小要依次增大。

LWIP_MALLOC_MEMPOOL_START 
LWIP_MALLOC_MEMPOOL(20, 256) 
LWIP_MALLOC_MEMPOOL(10, 512) 
LWIP_MALLOC_MEMPOOL(5, 1512) 
LWIP_MALLOC_MEMPOOL_END

好了,到此LWIP的內存管理部分算是簡單的學習了一下了,內存管理完。

2019-06-16 17:58:42

相關文章
相關標籤/搜索