Appearance
内存管理
选择
内存堆
lwIP内存堆是一种可变长分配策略,可以随意申请任意大小的内存
有三个函数
- mem_init()内存堆的初始化
- mem_malloc()申请内存堆
- mem_free()释放内存堆
主要的实现在mem.c文件里面
c
/**
* The heap is made up as a list of structs of this type.
* This does not have to be aligned since for getting its size,
* we only use the macro SIZEOF_STRUCT_MEM, which automatically aligns.
*/
//① ********************** 内存块控制块结构 *********************************************
struct mem {
/** index (-> ram[next]) of the next struct */
mem_size_t next; // 指向下一个节点
/** index (-> ram[prev]) of the previous struct */
mem_size_t prev; // 指向上一个节点
/** 1: this area is used; 0: this area is unused */
u8_t used; // 描述内存块是否可用 0 :未使用;1 :已使用
};
一个描述符结构体
c
/** All allocated blocks will be MIN_SIZE bytes big, at least!
* MIN_SIZE can be overridden to suit your needs. Smaller values save space,
* larger values could prevent too small blocks to fragment the RAM too much. */
//② ********************** 最小分配内存 ******************
#ifndef MIN_SIZE
#define MIN_SIZE 12
#endif /* MIN_SIZE */
c
/** Calculate memory size for an aligned buffer - returns the next highest
* multiple of MEM_ALIGNMENT (e.g. LWIP_MEM_ALIGN_SIZE(3) and
* LWIP_MEM_ALIGN_SIZE(4) will both yield 4 for MEM_ALIGNMENT == 4). 对齐计算
*/
#ifndef LWIP_MEM_ALIGN_SIZE
#define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1U) & ~(MEM_ALIGNMENT-1U))
#endif
/* some alignment macros: we define them here for better source code layout */
//③ ********************** 对齐操作 ******************
#define MIN_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MIN_SIZE) //最小分配内存大小对齐 --12字节
#define SIZEOF_STRUCT_MEM LWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) // 内存控制块对齐---8字节
#define MEM_SIZE_ALIGNED LWIP_MEM_ALIGN_SIZE(MEM_SIZE) // 内存堆对齐--lwipopts.h文件下MEM_SIZE配置项
c
/** the heap. we need one struct mem at the end and some room for alignment */
//④ ********************** 内存堆定义--大数组 ******************
//这一个使用的对齐方式是直接请求一个比对齐小1byte的区域
//之后可以使用这一个区域里面的对齐的位置
LWIP_DECLARE_MEMORY_ALIGNED(ram_heap, MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM));
// |
// |
// ram_heap[(((MEM_SIZE_ALIGNED + (2U * SIZEOF_STRUCT_MEM)) + MEM_ALIGNMENT - 1U))]
#define LWIP_RAM_HEAP_POINTER ram_heap //进行一次重命名
使用一个大数组作为可以使用的内存
c
//⑤ ********************** 内存堆所需要的指针变量 ******************
/** pointer to the heap (ram_heap): for alignment, ram is now a pointer instead of an array */
static u8_t *ram; // 指向内存堆对齐后起始地址
/** the last entry, always unused! */
static struct mem *ram_end; // 指向系统最后一个内存块
c
/** pointer to the lowest free block, this is used for faster search */
//⑥ ********************** 指向当前系统具有最低地址的空闲内存块 ******************
static struct mem * LWIP_MEM_LFREE_VOLATILE lfree;
释放的时候实际是吧记录当前空闲的lfree进行更改, 之后使用plug_holes函数判断一下前后的块是不是可以进行合并, 是的话进行合并
内存池
在使用的时候把内存分成多个大小相同的内存块, 使用链表进行连接, 使用的时候不需要切割, 直接进行分配, 释放的时候也不需要进行合并相邻的内存块
优点: 分配的速度快, 防止内存碎片化, 回收便捷
缺点: 浪费, 使用大内存的时候可能申请失败
memp_priv.h
定义结构体memp, 实际是一个链表项, 只有一个next成员
memp_desc, 记录内存池的每一个内存块的大小, 数量, 基地址, 以及第一个空闲块的链表
mem_std.h
根据使用的不同的模块, 初始化不同大小的内存池, 一般在lwipopts.h文件里面启用不同的模块
c
#define MEMP_NUM_UDP_PCB 6
#if LWIP_UDP
LWIP_MEMPOOL(UDP_PCB, MEMP_NUM_UDP_PCB, sizeof(struct udp_pcb), "UDP_PCB")
#endif /* LWIP_UDP */
memp.h
c
/** 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/priv/memp_std.h"
MEMP_MAX
} memp_t;
可以转换为
c
/** Create the list of all memory pools managed by memp. MEMP_MAX represents a NULL pool at the end */
typedef enum {
MEMP_UDP_PCB,
...
MEMP_MAX
} memp_t;
mem.c
c
#define LWIP_DECLARE_MEMORY_ALIGNED(variable_name, size) u8_t variable_name[LWIP_MEM_ALIGN_BUFFER(size)]
#define LWIP_MEM_ALIGN_BUFFER(size) (((size) + MEM_ALIGNMENT - 1U))
#define LWIP_MEMPOOL_DECLARE_STATS_INSTANCE(name)
#define MEMP_SIZE (LWIP_MEM_ALIGN_SIZE(sizeof(struct memp)) + MEM_SANITY_REGION_BEFORE_ALIGNED)
#define LWIP_MEMPOOL(name,num,size,desc) LWIP_MEMPOOL_DECLARE(name,num,size,desc)
#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 \
};
展开以后
c
#define LWIP_MEMPOOL_DECLARE(UDP_PCB, 6, sizeof(struct udp_pcb), "UDP_PCB") \
u8_t memp_memory_UDP_PCB_base[(6 * (sizeof(struct memp) + 16 + sizeof(struct memp))))]; \
static struct memp *memp_tab_UDP_PCB; \
const struct memp_desc memp_UDP_PCB = { \
UDP_PCB, \
6, \
memp_memory_UDP_PCB_base, \
&memp_tab_UDP_PCB \
};
c
const struct memp_desc *const memp_pools[MEMP_MAX] = {
#define LWIP_MEMPOOL(name,num,size,desc) &memp_ ## name,
#include "lwip/priv/memp_std.h"
};
|
|
| 展开后的代码
|
V
const struct memp_desc *const memp_pools[MEMP_MAX] = {
&memp_TCPIP_MSG_API,
&memp_TCPIP_MSG_INPKT,
.........
};
重要的函数
c
memp_init(); // 初始化
memp_malloc(); //获取某一个类型的内存池
memp_free(); //释放内存池
c
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]);
}
}
c
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; //记录第一个空闲位置
/* cast through void* to get rid of alignment warnings */
memp = (struct memp *)(void *)((u8_t *)memp + MEMP_SIZE + desc->size); //偏移到下一个位置
}
}
desc->tab会指向最后一个, memp->next指向前一个
c
void *
memp_malloc(memp_t type)
{
void *memp;
LWIP_ERROR("memp_malloc: type < MEMP_MAX", (type < MEMP_MAX), return NULL;);
memp = do_memp_malloc_pool(memp_pools[type]);
return memp;
}
之后实际就是对链表的操作