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

相关文章
相关标签/搜索