Lwip内存管理

Lwip的动态内存管理机制有三种:

◆glibc的内存分配策略

◆内存(HEAP)分配策略

◆内存池(POLL)分配策略


Lwip内存堆分配策略和glibc内存分配策略只能从其中选择一种。

/**  

  * MEM_LIBC_MALLOC==1: Use malloc/free/realloc provided by your C-library                                                      

  * instead of the lwip internal allocator. Can save code size if you  

  * already use it.  

  */ 

 #ifndef MEM_LIBC_MALLOC 

 #defineMEM_LIBC_MALLOC    0 

 #endif  

上述代码注释可知当MEM_LIBC_MALLOC1,使用的是c运行库中内存分配释放函数malloc\free\realloc。当MEM_LIBC_MALLOC0使用lwip内存堆分配策略。


内存堆分配

初始化

内存堆的初始化函数为mem_init,此函数主要功能是初始化堆内存的起始地址ram,剩余内存起始地址lfree,以及空闲内存链表。

/* align the heap */   

ram =(u8_t *)LWIP_MEM_ALIGN(LWIP_RAM_HEAP_POINTER);                                                                                 

/* initialize the start of the heap */   

mem =(struct mem*)(void *)ram; 

mem->next =  MEM_SIZE_ALIGNED; 

mem->prev =  0; 

mem->used =  0; 

/* initialize the end of the heap */   

ram_end =(struct mem*)(void *)&ram[MEM_SIZE_ALIGNED]; 

ram_end->used =  1; 

ram_end->next =  MEM_SIZE_ALIGNED; 

ram_end->prev =  MEM_SIZE_ALIGNED; 

/* initialize the lowest-free pointer to the start of the heap */ 

lfree =(struct mem*)(void *)ram; 


起始地址ram指向的是数组ram_heap的首地址,数组ram_heap的定义如下:

#ifndef LWIP_RAM_HEAP_POINTER 

 /** the heap. we need one struct mem at the end and some room for alignment */   

 u8_tram_heap[MEM_SIZE_ALIGNED+(2U*SIZEOF_STRUCT_MEM)+MEM_ALIGNMENT];                             

 #defineLWIP_RAM_HEAP_POINTER ram_heap  

 #endif /* LWIP_RAM_HEAP_POINTER */

 

经过初始化后ram_heap的内存布局如下图所示:


ram_heap内存布局

内存分配

Lwip中堆内存分配函数为mem_malloc,此函数ram_heap数组中分配参数指定大小的字节,如果分配成功,返回的是分配内存指针。

下面分析mem_malloc函数看具体的实现:

/* Expand the size of the allocated memory region so that we can                                                                              

  adjust for alignment. */  

size =LWIP_MEM_ALIGN_SIZE(size); 

if (size <MIN_SIZE_ALIGNED) { 

    /* every data block must be at least MIN_SIZE_ALIGNED long */   

    size =MIN_SIZE_ALIGNED; 

}   

对于参数size首先需要需要扩展MEM_ALIGNMENT字节对齐。size值不能够小于MIN_SIZE字节,代码中定义为12字节,正好等于SIZEOF_STRUCT_MEM,用于存放struct mem结构体的内容


for (ptr=(mem_size_t)((u8_t *)lfree -  ram);ptr<MEM_SIZE_ALIGNED-  size; 

                    ptr =((struct mem*)(void *)&ram[ptr])->next) { 

    mem =(struct mem*)(void *)&ram[ptr]; 

    if ((!mem->used) && (mem->next -(ptr+SIZEOF_STRUCT_MEM)) >=size) {  

        if (mem->next -(ptr+SIZEOF_STRUCT_MEM)>=(size +SIZEOF_STRUCT_MEM+MIN_SIZE_ALIGNED)) {             

            ptr2 =ptr+SIZEOF_STRUCT_MEM+size;    

            mem2 =(struct mem*)(void *)&ram[ptr2]; 

            mem2->used =  0; 

            mem2->next =  mem->next; 

            mem2->prev =  ptr; 

            mem->next =  ptr2; 

            mem->used =  1;

            if (mem2->next !=MEM_SIZE_ALIGNED) { 

                ((struct mem*)(void *)&ram[mem2->next])->prev =  ptr2; 

            }  

        } else {  

            mem->used =  1; 

        }  

外层的for循环遍历lfree开始内存空间,直到找到一个比size个字节大的空闲内存空间。mem结构体起始地址就是lfree开始的堆内存空间地址,如果mem->used0表示这段内存空间空闲如果mem指向的下段内存的起始地址mem起始地址之间大于size+SIZEOF_STRUCT_MEM,则表示找到一个满足条件的可用空闲内存空间。



找到一个满足size字节大小的可用空闲内存空间后,还存在两种情况:

情况一:

这片空闲内存空间大,满足如下条件

mem->next - (ptr + SIZEOF_STRUCT_MEM) >= (size + SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED)


这片内存空间分成两部分,链表连接起来,并将前面mem->used设置1

情况二:

这片空闲内存空间内存在分配size+SIZEOF_STRUCT_MEM大小之后,剩余空间小于SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED,这样直接将mem->used设置1即可


上面代码可知lwip的动态内存分配就是从ram_heap数组中找到一个比所申请size的空间内存空间,就从切割出合适的内存空间,并将剩余的的返回给堆内存,以备后面之用


内存池分配策略

内存池有很多种,从memp_std.h文件就可看到RAW_PCB、UDP_PCB、TCP_PCB等等,每种类型的内存池单个大小固定的。

const struct memp_desc* constmemp_pools[MEMP_MAX]={ 

 #defineLWIP_MEMPOOL(name,num,size,desc)&memp_ ## name,                                                                  

 #include"lwip/priv/memp_std.h"  

};


内存池由memp_pools全局数组进行管理数组大小为MEMP_MAX,此值就是所有类型的内存池的个数,它是枚举memp_std.h文件中所有类型的内存池得到的。

typedef enum { 

 #defineLWIP_MEMPOOL(name,num,size,desc)  MEMP_##name,                                                                     

 #include"lwip/priv/memp_std.h"  

   MEMP_MAX  

 }memp_t; 

memp_pools数组的成员对应类型的内存池地址,结合memp_std.h就会看到:

memp_pools[0] = &memp_RAW_PCB

那memp_ ## name值是如何定义的呢?

#define LWIP_MEMPOOL_DECLARE(name,num,size,desc)u8_tmemp_memory_ ## name ## _base\                      

     [((num) *(MEMP_SIZE+MEMP_ALIGN_SIZE(size)))];\  

     \  

   staticstruct memp *memp_tab_ ##name;\  

     \  

   conststruct memp_descmemp_ ##name ={\  

     LWIP_MEM_ALIGN_SIZE(size),\  

     (num),\  

     DECLARE_LWIP_MEMPOOL_DESC(desc)\  

     memp_memory_ ## name ## _base,\  

     &memp_tab_ ##name \  

   }; 

这个宏看起来比较难懂,它首先定义了一个unsigned char的数组memp_memory_ ## name ## _base,数组大小为此种类型内存池num *(此种类型内存池固定大小size + memp管理区大小MEMP_SIZE)乘积。

接着定义了一个类型为struct mempstatic指针变量memp_tab_ ## name。

最后定义了类型为struct memp_desc的常量memp_ ## name,并对此常量进行了初始化。memp_TCP_PCB变量的各成员示例如下:


size成员大小为232等于struct tcp_pcb结构体大小。

num成员5表示此内存池内存分为5个部分。

base成员memp_TCP_PCB类型内存池地址

tab成员指针用来链接此内存池的5部分。


这里memp_memory_TCP_PCB_base数组首地址为0x6813c0,分成5部分,每个部分的首地址如下所示


此种类型内存池结构图如下所示:


初始化

内存池的初始化函数为memp_init,首先会初始化MEMP_MAX个不同类型内存池的统计信息也就是初始化lwip_stats.memp数组。接下来就是调用memp_init_pool函数初始化MEMP_MAX个不同类型内存池的struct memp_desc结构体信息



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值