• 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的定义如下,看完继续懵逼中。。。,但是不能慌一个个宏替换出来

    #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 
      };

    然后就是这样子的宏替换,此处未全部列举

    #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
      };  
    .
    .
    .

    ,同理理解到这里下面继续第二个宏就是同理结果如下

    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;

    然后这里还还需要了解一个结构体的定义如下,

    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

  • 相关阅读:
    正则表达式验证手机号
    windows redis 安装启动及设置密码
    c# MVC利用AuthorizeAttribute验证用户是否登录
    判断页面是否加载完成
    关于List的ConcurrentModificationException
    intellij idea 12 编码不可映射字符
    这年头,竞争压力这么大,为什么我啥都想学。
    关于学习
    盘点8种CSS实现垂直居中水平居中的绝对定位居中技术
    单点登录原理与简单实现
  • 原文地址:https://www.cnblogs.com/w-smile/p/11032337.html
Copyright © 2020-2023  润新知