LWIP再探----内存池管理
這這里是接上一篇內(nèi)存池管理部分的,這里如果讀者一打開memp.c的話會感覺特別那一理解原作者在干嘛,但是看懂了就明白原作者是怎么巧妙的使用了宏。廢話不多說先說了下我分析是一下宏的條件是
前提條件
MEMP_STATS = 0
MEMP_OVERFLOW_CHECK = 0
首先要去簡單的看下#include "lwip/priv/memp_std.h"文件的格式,只需要明白這個文件依賴LWIP_MEMPOOL(name,num,size,desc)這個宏,并且在文件結(jié)尾將宏清除。
因此出現(xiàn)底下的最難的兩塊
#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" };先說第一個,繼續(xù)追LWIP_MEMPOOL_DECLARE的定義如下,看完繼續(xù)懵逼中。。。,但是不能慌一個個宏替換出來
#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 \};里面相關(guān)宏的實現(xiàn)匯總?cè)缦?/p> #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\ };然后就是這樣子的宏替換,此處未全部列舉
#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}; . . .,同理理解到這里下面繼續(xù)第二個宏就是同理結(jié)果如下
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是這樣來的
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;然后這里還還需要了解一個結(jié)構(gòu)體的定義如下,
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的內(nèi)存串到了一個結(jié)構(gòu)體數(shù)組中。要注意此時每個memp_pools中的memp_desc結(jié)構(gòu)體中的memp_tab_UDP_PCB還只是一個指針的指針,并未有具體的實際意義。然后memp_init會進(jìn)行這一工作,去掉宏不編譯的部分
memp_init如下
就是循環(huán)調(diào)用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} }到這里所有內(nèi)存池的定義和初始化已經(jīng)完成了借用野火的一張圖,初始化后的pool結(jié)構(gòu)如下
每一個類型的池最后由,tab將所有的空閑池串起來,組成一個內(nèi)存池單向鏈表。到此最難理解的部分已經(jīng)完了,接下來內(nèi)存池的內(nèi)存分配和釋放就是很簡單的內(nèi)容了。
內(nèi)存申請
void * memp_malloc(memp_t type){void *memp;// 取對應(yīng)內(nèi)存池的控制塊memp = do_memp_malloc_pool(memp_pools[type]);return memp; } //這個函數(shù)內(nèi)部實際上調(diào)用了 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的頭,所以內(nèi)存申請直接就是返回tab指向pool就可以了。同時內(nèi)存釋放就是將pool從新插入單向鏈表的操作了。具體簡化的代碼如下
內(nèi)存釋放
void memp_free(memp_t type, void *mem) {if (mem == NULL) {return;}do_memp_free_pool(memp_pools[type], mem);} //調(diào)用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);}現(xiàn)在LWIP的兩種內(nèi)存策略的實現(xiàn)方式,都已經(jīng)理解過了,其中內(nèi)存池的溢出檢測部分沒有說,但是已經(jīng)可以幫助我們使用LWIP了,作者設(shè)計兩種內(nèi)存策略是有他的設(shè)計初衷的,看了#include "lwip/priv/memp_std.h"文件就知道,內(nèi)存池的出現(xiàn)就是為一些特殊的長度固定的數(shù)據(jù)結(jié)構(gòu)設(shè)計的,他分配快速,釋放亦是,并且很定不會有內(nèi)存碎片,但是這還是一種空間換時間的做法,因為內(nèi)存池申請函數(shù),支持如果當(dāng)前尺寸的pool用完了,可以分配更大的池。內(nèi)存堆就是用來應(yīng)對大小不定的內(nèi)存分配場合的,當(dāng)人LWIP支持用堆實現(xiàn)pool也支持用pool實現(xiàn)堆,同時還支持用戶池,這些功能都可以通過宏簡單 的配置具體如下
MEM_LIBC_MALLOC? 使用C庫
MEMP_MEM_MALLOC? 使用內(nèi)存堆替換內(nèi)襯池。
MEM_USE_POOLS? 使用內(nèi)存池替換內(nèi)存堆
MEMP_USE_CUSTOM_POOLS? ?使用用戶定義的內(nèi)存池,這個實現(xiàn)需要用戶提供一個文件lwippools.h,并按如下形式定義字節(jié)的內(nèi)存池,要求內(nèi)存池的大小要依次增大。
LWIP_MALLOC_MEMPOOL_START LWIP_MALLOC_MEMPOOL(20, 256) LWIP_MALLOC_MEMPOOL(10, 512) LWIP_MALLOC_MEMPOOL(5, 1512) LWIP_MALLOC_MEMPOOL_END好了,到此LWIP的內(nèi)存管理部分算是簡單的學(xué)習(xí)了一下了,內(nèi)存管理完。
2019-06-16 17:58:42
?
轉(zhuǎn)載于:https://www.cnblogs.com/w-smile/p/11032337.html
總結(jié)
以上是生活随笔為你收集整理的LWIP再探----内存池管理的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: 【基础算法-模拟-例题-*校长的问题】-
- 下一篇: Python学习教程:Python爬虫抓