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结构体信息



INTRODUCTION lwIP is a small independent implementation of the TCP/IP protocol suite. The focus of the lwIP TCP/IP implementation is to reduce the RAM usage while still having a full scale TCP. This making lwIP suitable for use in embedded systems with tens of kilobytes of free RAM and room for around 40 kilobytes of code ROM. lwIP was originally developed by Adam Dunkels at the Computer and Networks Architectures (CNA) lab at the Swedish Institute of Computer Science (SICS) and is now developed and maintained by a worldwide network of developers. FEATURES * IP (Internet Protocol, IPv4 and IPv6) including packet forwarding over multiple network interfaces * ICMP (Internet Control Message Protocol) for network maintenance and debugging * IGMP (Internet Group Management Protocol) for multicast traffic management * MLD (Multicast listener discovery for IPv6). Aims to be compliant with RFC 2710. No support for MLDv2 * ND (Neighbor discovery and stateless address autoconfiguration for IPv6). Aims to be compliant with RFC 4861 (Neighbor discovery) and RFC 4862 (Address autoconfiguration) * DHCP, AutoIP/APIPA (Zeroconf), ACD (Address Conflict Detection) and (stateless) DHCPv6 * UDP (User Datagram Protocol) including experimental UDP-lite extensions * TCP (Transmission Control Protocol) with congestion control, RTT estimation fast recovery/fast retransmit and sending SACKs * raw/native API for enhanced performance * Optional Berkeley-like socket API * TLS: optional layered TCP ("altcp") for nearly transparent TLS for any TCP-based protocol (ported to mbedTLS) (see changelog for more info) * PPPoS and PPPoE (Point-to-point protocol over Serial/Ethernet) * DNS (Domain name resolver incl. mDNS) * 6LoWPAN (via IEEE 802.15.4, BLE or ZEP) APPLICATIONS * HTTP server with SSI and CGI (HTTPS via altcp) * SNMPv2c agent with MIB compiler (Simple Network Management Protocol), v3 via altcp * SNTP (Simple network time protocol) * NetBIOS name service responder * MDNS (Multicast DNS) responder * iPerf server implementation * MQTT client (TLS support via altcp) LICENSE lwIP is freely available under a BSD license. DEVELOPMENT lwIP has grown into an excellent TCP/IP stack for embedded devices, and developers using the stack often submit bug fixes, improvements, and additions to the stack to further increase its usefulness. Development of lwIP is hosted on Savannah, a central point for software development, maintenance and distribution. Everyone can help improve lwIP by use of Savannah's interface, Git and the mailing list. A core team of developers will commit changes to the Git source tree. The lwIP TCP/IP stack is maintained in the 'lwip' Git module and contributions (such as platform ports) are in the 'contrib' Git module. See doc/savannah.txt for details on Git server access for users and developers. The current Git trees are web-browsable: http://git.savannah.gnu.org/cgit/lwip.git http://git.savannah.gnu.org/cgit/lwip/lwip-contrib.git Submit patches and bugs via the lwIP project page: http://savannah.nongnu.org/projects/lwip/ Continuous integration builds (GCC, clang): https://travis-ci.org/lwip-tcpip/lwip DOCUMENTATION Self documentation of the source code is regularly extracted from the current Git sources and is available from this web page: http://www.nongnu.org/lwip/ Also, there are mailing lists you can subscribe at http://savannah.nongnu.org/mail/?group=lwip plus searchable archives: http://lists.nongnu.org/archive/html/lwip-users/ http://lists.nongnu.org/archive/html/lwip-devel/ There is a wiki about lwIP at http://lwip.wikia.com/wiki/LwIP_Wiki You might get questions answered there, but unfortunately, it is not as well maintained as it should be. lwIP was originally written by Adam Dunkels: http://dunkels.com/adam/ Reading Adam's papers, the files in docs/, browsing the source code documentation and browsing the mailing list archives is a good way to become familiar with the design of lwIP. Adam Dunkels Leon Woestenberg
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值