LWIP内存池memp.h头文件学习

声明:个人所写所有博客均为自己在学习中的记录与感想,或为在学习中总结他人学习成果,但因本人才疏学浅,如果大家在阅读过程中发现错误,欢迎大家指正。
公众号:
LWIP内存池memp.h头文件学习_第1张图片

使用LWIP源码版本为1.4.1


关于动态内存池分配

动态内存池分配策略实现起来非常简单。内存的分配、释放效率高,不像内存堆那样产生大量的内存碎片,有效防止碎片的产生,这种方式下,用户只能申请到大小固定的空间。在LWIP中,这种方式主要用于内核中固定数据结构的分配,例如UDP控制块、TCP控制块等,内核在初始化时已经为每个数据结构类型都初始化好了一定数量的POOL。源文件memp.h和memp.c包含了实现动态内存池分配策略的所有数据结构和函数。
——引自《嵌入式网络那些事:LwIP协议深度剖析与实战演练》(朱升林)

动态内存池管理相关数据结构

名称 类型 所在文件 描述
memp_t 枚举数据类型 memp.h 为每一个POOL定义一个名称/编号
memp_tab[] 全局型指针数组 memp.c 指向每类POOL中的第一个POOL
memp_sizes[] 全局型数组 memp.c 每类POOL中单个POOL的大小
memp_num[] 全局型数组 memp.c 每类POOL中POOL的个数
memp_desc[] 全局型指针数组 memp.c 指向每类POOL的描述字符串
memp_memory[] 全局型数组 memp.c 为所有POOL分配的内存空间

关于枚举类型memp_t

/* Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */
typedef enum {
	#define LWIP_MEMPOOL(name, num, size, desc) MEMP_##name,
	#include "lwip/memp_std.h"
	MEMP_MAX 
} memp_t;

通过各种内存池的唯一的名称定义一个enum,并且在最后插入MEMP_MAX来得到内存池的总数。
这段代码中的中的宏定义,它告诉编译器,如果遇到LWIP_MEMPOOL(name, num, size, desc)这个宏的时候,就把它用“MEMP_##name“来代替,双井号”##“在C语言中被称为连接符,真真的我也是第一次遇到,以前看书的时候从没注意过,也没见过其他地方用了。我又回去翻看了下丹尼斯·里奇老爷爷写的《C程序设计语言》。

以下是《C程序设计语言》中的原文:
预处理运算符 ##为宏扩展提供了一种连接实际变元的手段。如果替换文本中的参数用##相连,那么参数就被实际变元替换, ##与前后的空白符被删除,并对替换后的结果重新扫描,例如,下面的宏paste用于连接两个变元:
’ #define paste(front, back) front ## back’
从而宏调用paste(name, 1)的结果是建立单词name1。

也就是如果以后编译过程中编译器遇到下面这样一句C语句,会将它替换为“MEMP_example1”
LWIP_MEMPOOL(example1, num1, size1, desc1)

接下来,#include “memp_std.h”,则编译器会马上找到该文件并编译它,编译完该头文件后,枚举类型memp_t就被定义出来了。这个头文件是对各种内存池的描述。
memp_std.h文件主要是由三种内存池组成:

  • Lwip_MEMPOOL 标准的内存池
  • LWIP_MALLOC_MEMPOOL 被mem.c中mem_malloc使用的内存池,需要在lwippool.h自定义不同大小的内存池
  • LWIP_PBUF_MEMPOOL PBUF的内存池

文件memp_std.h本质是由多个LWIP_MEMPOOOL宏组成,所以编译器依次对他们进行替换,这样当memp_std.h编译完之后,memp_t就建立起来,本质是:

typedef enum {
	MEMP_RAW_PCB,
	MEMP_UDP_PCB,
	MEMP_TCP_PCB,
	MEMP_TCP_PCB_LISTEN,
	MEMP_TCP_SEG,
	........
	MEMP_MAX
} memp_t;

其中的MEMP_MAX并不代表任何类型的POOL,但是这里代表了该枚举类型中的元素的总个数。

其他

memp_size[MEMP_MAX]数组存放每个内存池的节点大小

你可能感兴趣的:(LwIP)