LwIP 协议栈源码分析(读书笔记)--内存管理--动态内存池POOL分配策略源码

本章分析动态内存堆(HEAP)的第一种分配策略,承接上篇文章
LwIP 协议栈源码分析(读书笔记)–内存管理–机制策略分析
LwIP 协议栈源码分析(读书笔记)–内存管理–动态内存堆(HEAP)分配策略源码

组织结构:

这里写图片描述

源码解析:

见wlip memp.c文件。
必要的结构解释:
内存池大小=单个内存类型1大小数目1+单个内存类型2大小数目2+……+单个内存类型MEMP_MAX*数目MEMP_MAX,
内存池元素个数=数目1+数目MEMP_MAX;

/** This array holds the first free element of each pool.
 *  Elements form a linked list.==该数组保存一张链表,节点数=MEMP_MAX种类型的内存类型*对应的数目,即内存池元素个数 */
static struct memp *memp_tab[MEMP_MAX];
/** This array holds the number of elements in each pool. ==该数组包含了每种内存类型的数目*/
static const u16_t memp_num[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc)  (num),
#include "lwip/memp_std.h"
};
/** This array holds the element sizes of each pool. ==该数组包含了每种内存类型结构的单个大小(不与数目相乘)*/
#if !MEM_USE_POOLS && !MEMP_MEM_MALLOC
static
#endif
const u16_t memp_sizes[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc)  LWIP_MEM_ALIGN_SIZE(size),
#include "lwip/memp_std.h"
};

memp_init():



/**
 * Initialize this module.
 * 
 * Carves out memp_memory into linked lists for each pool-type.
 */
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]);
  }

#if !MEMP_SEPARATE_POOLS
  memp = (struct memp *)LWIP_MEM_ALIGN(memp_memory);//内存地址对齐
#endif /* !MEMP_SEPARATE_POOLS */
  /* for every pool: */
  for (i = 0; i < MEMP_MAX; ++i) {//创建链表:节点数=MEMP_MAX种类型的内存类型*对应的数目 
    memp_tab[i] = NULL;
#if MEMP_SEPARATE_POOLS
    memp = (struct memp*)memp_bases[i];
#endif /* MEMP_SEPARATE_POOLS */
    /* create a linked list of memp elements==创建memp链表==将memp_num[i]个相同内存类型之间 建立链表连接,由后向前 */
    for (j = 0; j < memp_num[i]; ++j) {
      memp->next = memp_tab[i];
      memp_tab[i] = memp;
      memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + memp_sizes[i]//更新memp为下一个块地址
#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 */
}

memp_malloc():


/**
 * Get an element from a specific pool.
 *
 * @param type the pool to get an element from
 *
 * the debug version has two more parameters:
 * @param file file name calling this function
 * @param line number of line where this function is called
 *
 * @return a pointer to the allocated memory or a NULL pointer on error
 */
void *
#if !MEMP_OVERFLOW_CHECK
memp_malloc(memp_t type)
#else
memp_malloc_fn(memp_t type, const char* file, const int line)
#endif
{
  struct memp *memp;
  SYS_ARCH_DECL_PROTECT(old_level);

  LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);

  SYS_ARCH_PROTECT(old_level);
#if MEMP_OVERFLOW_CHECK >= 2
  memp_overflow_check_all();
#endif /* MEMP_OVERFLOW_CHECK >= 2 */

  memp = memp_tab[type];//获取内存类型的首地址

  if (memp != NULL) {
    memp_tab[type] = memp->next;//更新memp_tab
#if MEMP_OVERFLOW_CHECK
    memp->next = NULL;
    memp->file = file;
    memp->line = line;
#endif /* MEMP_OVERFLOW_CHECK */
    MEMP_STATS_INC_USED(used, type);
    LWIP_ASSERT("memp_malloc: memp properly aligned",
                ((mem_ptr_t)memp % MEM_ALIGNMENT) == 0);
    memp = (struct memp*)(void *)((u8_t*)memp + MEMP_SIZE);//类型强转
  } else {
    LWIP_DEBUGF(MEMP_DEBUG | LWIP_DBG_LEVEL_SERIOUS, ("memp_malloc: out of memory in pool %s\n", memp_desc[type]));
    MEMP_STATS_INC(err, type);
  }

  SYS_ARCH_UNPROTECT(old_level);

  return memp;
}

memp_free():


/**
 * Put an element back into its pool.
 *
 * @param type the pool where to put mem
 * @param mem the memp element to free
 */
void
memp_free(memp_t type, void *mem)
{
  struct memp *memp;
  SYS_ARCH_DECL_PROTECT(old_level);

  if (mem == NULL) {
    return;
  }
  LWIP_ASSERT("memp_free: mem properly aligned",
                ((mem_ptr_t)mem % MEM_ALIGNMENT) == 0);

  memp = (struct memp *)(void *)((u8_t*)mem - MEMP_SIZE);

  SYS_ARCH_PROTECT(old_level);

#if MEMP_OVERFLOW_CHECK
#if MEMP_OVERFLOW_CHECK >= 2
  memp_overflow_check_all();
#else
  memp_overflow_check_element_overflow(memp, type);
  memp_overflow_check_element_underflow(memp, type);
#endif /* MEMP_OVERFLOW_CHECK >= 2 */
#endif /* MEMP_OVERFLOW_CHECK */

  MEMP_STATS_DEC(used, type); 

  memp->next = memp_tab[type]; //插入链表
  memp_tab[type] = memp;

#if MEMP_SANITY_CHECK
  LWIP_ASSERT("memp sanity", memp_sanity());
#endif /* MEMP_SANITY_CHECK */

  SYS_ARCH_UNPROTECT(old_level);

}

问:

lwip 内存池的组织形式为链表,但链表本身的内存在哪里?看代码实现,他是在池中。如果这样,数据岂不是全乱套了?

不会乱套,每个池子最前面的4个字节用做指针;内存被分配后,这四个字节可以用来存储数据。这个时候被分配的块已经不在链表上了,所以指针不会保留,也没必要保留。

有人说,lwip内存池会浪费内存,但lwip实现的池,是已规划的很好的,按理来说,使用合理,还会浪费么?

这里的浪费的概念是比如系统保留了五个,但实际你只会用到三个。有两个预留的空间永远不会用到。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值