http://lwip.wikia.com/wiki/Lwipopts.h
/** * 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 #define MEM_LIBC_MALLOC 0 #endif /** * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set * of memory pools of various sizes. When mem_malloc is called, an element of * the smallest pool that can provide the length needed is returned. * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. defines additional pools */ #ifndef MEM_USE_POOLS #define MEM_USE_POOLS 0 #endif /** * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h * that defines additional pools beyond the "standard" ones required * by lwIP. If you set this to 1, you must have lwippools.h in your * inlude path somewhere. */ #ifndef MEMP_USE_CUSTOM_POOLS #define MEMP_USE_CUSTOM_POOLS 0 #endif
-------------------------------------------------------------------------------------------------------------
MEM_LIBC_MALLOC == 1 : the standard C library :
HEAP
malloc(), realloc(), calloc(), free()
-------------------------------------------------------------------------------------------------------------
MEM_LIBC_MALLOC == 0, MEM_USE_POOLS == 0 : lwIP replacement for your libc malloc() :
u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT];
mem_init(), mem_malloc(), mem_calloc(), mem_free(), mem_trim()
-------------------------------------------------------------------------------------------------------------
MEM_LIBC_MALLOC == 0, MEM_USE_POOLS == 1 : lwIP head implemented with different sized pools
/** This is the actual memory used by the pools (all pools in one big block). */
static u8_t memp_memory[MEM_ALIGNMENT - 1
#define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) )
#include "lwip/memp_std.h"
];
mem_malloc(), mem_free() --> memp_malloc(), memp_free() in memp.c
memp_std.h :
/* * Allow for user-defined pools; this must be explicitly set in lwipopts.h * since the default is to NOT look for lwippools.h */ #if MEMP_USE_CUSTOM_POOLS #include "lwippools.h" #endif /* MEMP_USE_CUSTOM_POOLS */
lwippools.h
/* Define three pools with sizes 256, 512, and 1512 bytes */ LWIP_MALLOC_MEMPOOL_START LWIP_MALLOC_MEMPOOL(20, 256) LWIP_MALLOC_MEMPOOL(10, 512) LWIP_MALLOC_MEMPOOL(5, 1512) LWIP_MALLOC_MEMPOOL_END /* My sys_arch uses memory pools to allocate mbox and sems */ LWIP_MEMPOOL(SYS_MBOX, 22, sizeof(struct sys_mbox_struct), "SYS_MBOX") LWIP_MEMPOOL(SYS_SEM, 12, sizeof(struct sys_sem_struct), "SYS_SEM")
In an embedded environment, memory pools make for fast and efficient memory allocation.
lwIP provides a flexible way to manage memory pool sizes and organization.
lwIP reserves a fixed-size static chunk of memory in the data segment,
which is subdivided into the various pools that lwip uses for the various data structures.
For example, there is a pool just for struct tcp_pcb
's, and another pool just for struct udp_pcb
's.
Each pool can be configured to hold a fixed number of data structures;
this number can be changed in the lwipopts.h file by changing the variousMEMP_NUM_*
values.
For example, MEMP_NUM_TCP_PCB
and MEMP_NUM_UDP_PCB
control the maximum number of tcp_pcb
and udb_pcb
structures
that can be active in the system at any given time.
It is also possible to create custom memory pools in addition to the standard ones provided by lwIP.
lwIP uses a custom function mem_malloc
for all dynamic allocation; therefore, it is easy to change how lwIP uses its RAM.
There are three possibilities provided out-of-the-box:
mem_malloc
. [static array ram_heap]MEM_SIZE
to change the size of the lwIP heap.malloc
and free
. [ alloc from HEAP ]MEM_LIBC_MALLOC
.mem_malloc [static array memp_memory]
MEM_USE_POOLS
and MEMP_USE_CUSTOM_POOLS
and a new custom file lwippools.h
.lwIP uses memory for:
Unless you use a C library heap implementation (by defining MEM_LIBC_MALLOC to 1), dynamically allocated memory must be statically allocated somewhere.
This means you reserve a specific amount of memory for the heap or the memp pools from which the code dynamically allocates memory at runtime.
If you then even define MEM_LIBC_MALLOC to 1, too, lwIP doesn't need extra memory for dynamically allocated memory but only uses the C library heap instead.
However, you then have to make sure that this heap is big enough to run your application.
The size of this heap and memp pools can be adjusted to save RAM:
However, if you define MEMP_MEM_MALLOC to 1 in your lwipopts.h,
*every* piece of dynamically allocated memory will come from the *heap* (the size of which is defined by MEM_SIZE).
-- this is the *heap* and it is allocated as mem_memory.
To tweak the various MEMP_NUM_ defines, define LWIP_STATS=1 and LWIP_STATS_DISPLAY=1 and
call stats_display() to see how many entries of each pool are used (or have a look at the global variable lwip_stats instead).
lwIP provides a way to define your own custom memory pools to be used in addition to the standard ones provided by lwIP.
There are two reasons you may need to do this:
mem_malloc
, as described in the next section
The standard memory pools are defined in the memp_std.h
file.
If you define the MEMP_USE_CUSTOM_POOLS
macro, then lwIP will also search for a lwippools.h
file.
This file should be created in the same directory as lwipopts.h
and only needs to contain additional pools not defined in memp_std.h
.
There are three "kinds" of pools that can be defined:
LWIP_MEMPOOL(pool_name, number_elements, element_size, pool_desc)
. LWIP_PBUF_MEMPOOL(pool_name, number_elements, payload_size, pool_desc)
. pbuf_alloc
.LWIP_MALLOC_MEMPOOL(number_buffers, buffer_size)
. mem_malloc
(see next section).
Simply include a definition in your lwippools.h
file for each additional pool you want to be included in lwIP's memory subsystem.
An example is provided at the end of this chapter.
/* Define three pools with sizes 256, 512, and 1512 bytes */ LWIP_MALLOC_MEMPOOL_START LWIP_MALLOC_MEMPOOL(20, 256) LWIP_MALLOC_MEMPOOL(10, 512) LWIP_MALLOC_MEMPOOL(5, 1512) LWIP_MALLOC_MEMPOOL_END /* My sys_arch uses memory pools to allocate mbox and sems */ LWIP_MEMPOOL(SYS_MBOX, 22, sizeof(struct sys_mbox_struct), "SYS_MBOX") LWIP_MEMPOOL(SYS_SEM, 12, sizeof(struct sys_sem_struct), "SYS_SEM")
mem_malloc
To enable a pool-based mem_malloc
, you must first define a set of chunk sizes.
When lwIP calls mem_malloc for a block of size "x", it will attempt to allocate a chunk of size at least as big as "x".
For example, if your chunk sizes are 256 (for small blocks), 512 (for medium blocks) and 1512 (for full Ethernet frames),
then calling mem_malloc for blocks of size 100, 400, and 1000 will result in a block of each size.
The example below shows how to do this setup.
The definitions for all malloc memory pools must be made contiguously as a single group,
starting with a LWIP_MALLOC_MEMPOOL_START
and ending with a LWIP_MALLOC_MEMPOOL_END
.
WARNING:
The memory pool allocator will pick the first pool size that fits the requested size,
testing them in the order that you list them in the lwippools.h
file.
Therefore, you probably want to list them in order of increasing size!
If the allocation fails, it does not test pools later on in the list.
/* Define three pools with sizes 256, 512, and 1512 bytes */ LWIP_MALLOC_MEMPOOL_START LWIP_MALLOC_MEMPOOL(20, 256) LWIP_MALLOC_MEMPOOL(10, 512) LWIP_MALLOC_MEMPOOL(5, 1512) LWIP_MALLOC_MEMPOOL_END /* My sys_arch uses memory pools to allocate mbox and sems */ LWIP_MEMPOOL(SYS_MBOX, 22, sizeof(struct sys_mbox_struct), "SYS_MBOX") LWIP_MEMPOOL(SYS_SEM, 12, sizeof(struct sys_sem_struct), "SYS_SEM")// LWIP_MEMPOOL( pool_name, number_elements, element_size, pool_desc)
.
This is a lightweight replacement for the standard C library malloc().
If you want to use the standard C library malloc() instead, define MEM_LIBC_MALLOC to 1 in your lwipopts.h
To let mem_malloc() use pools (prevents fragmentation and is much faster than a heap but might waste some memory),
define MEM_USE_POOLS to 1, define MEM_USE_CUSTOM_POOLS to 1 and
create a file "lwippools.h" that includes a list of pools like this (more pools can be added between _START and _END):
* Define three pools with sizes 256, 512, and 1512 bytes
* LWIP_MALLOC_MEMPOOL_START
* LWIP_MALLOC_MEMPOOL(20, 256)
* LWIP_MALLOC_MEMPOOL(10, 512)
* LWIP_MALLOC_MEMPOOL(5, 1512)
* LWIP_MALLOC_MEMPOOL_END
lwIP has dedicated pools for many structures (netconn, protocol control blocks,* packet buffers, ...).
All these pools are managed here.
内存池 (Memory Pool),又被称为固定大小区块规划 (fixed-size-blocks allocation),
允许程序员以类似 C语言 的 malloc 或是 C++ 的 new 运算对象进行动态的存储器规划。
对于其它动态存储器规划的实践来说,因为会变动存储器区块大小导致的碎片问题,导致在实时系统上受限于性能因此,
根本无法使用。内存池'提供了一个更有效率的解决方案:预先规划一定数量的存储器区块,
使得整个程序可以在运行期规划 (allocate)、使用 (access)、归还 (free) 存储器区块。
优点
缺点
http://blog.csdn.net/wjjontheway/article/details/9089729
LwIP中的有两种方式的内存,heap和pool。老衲五木的《LwIP协议栈源码详解》将heap称之为动态内存堆,将pool称为动态内存池。
heap像是一块蛋糕,分配的时候容易产生碎片,因为你只能看,看完之后还得还回去,当等待切的人多了并且大小不一定时,容易产生很多细小的碎片,
当你需要切一块较大的蛋糕时,发现没有符合你需要的蛋糕块,因此内存申请频频失败。
pool是对一整块蛋糕进行均分,进行统一大小的分配。如果你使用的数据小于蛋糕的容量,那也只好使用它。
如果大于一块蛋糕的容量,就得多申请一块或者更多。有个问题就是pool蛋糕的均分,分的太小容易,内存利用率降低;切得太大,内存严重浪费。
Pool型一般用于从链路层就收一个帧,目的是快速、少碎片、浪费一点没关系。(prevents fragmentation and is much faster than a heap but might waste some memory)
Heap型一般用于缓存应用层生成的数据,大小自己定,相切多少切多少,随心所欲,尽管以后可能没得切,但我只在乎现在,也许以后就有新的方法解决呢。
LwIP内存分配有三种方法:
1.C库自带的内存分配策略 <HEAP> <MEM_LIBC_MALLOC==1>
2.动态内存堆(Heap)分配策略 <Static ARRAY> <MEM_LIBC_MALLOC==1, MEM_USE_POOLS==0
>
3.动态内存池(Pool)分配策略<Static ARRAY> <MEM_LIBC_MALLOC==1, MEM_USE_POOLS==1
>
在配置时,有两个文件opt.h和lwipopts.h需要关注。
“opt.h是lwip“出厂”时原装的配置文件,
lwipopts.h集合了opt.h中常常需要改动的部分。
这两个文件里边都配置的选项,以后者为准,不是共有的选项以它们各自的配置为准。”
在opt.h中,有如下片段
/*------------------------------------ ---------- Memory options ---------- ------------------------------------*/ /** * 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 #define MEM_LIBC_MALLOC 0 #endif
当MEM_LIBC_MALLOC定义为1时,使用C库自带的内存分配策略,
当MEM_LIBC_MALLOC定义0时,使用LwIP自身的动态分配策略。
而动态内存分配策略可以有两种实现方式,
第一种就是如前所述的通过开辟一个内存堆,然后通过模拟C运行时库的内存分配策略来实现。
第二种就是通过动态内存池的方式来实现,也即动态内存分配函数通过简单调用动态内存池(POOL)分配函数来完成其功能”。
如果需要使用Pool分配函数,则需要同时定义MEM_USE_POOLS和MEMP_USE_CUSTOM_POOLS为1.
在opt.h中定义了该值,所以此处不使用第二种通过内存池Pool分配。一般情况下,使用第一种分配策略实现。
/** * MEM_USE_POOLS==1: Use an alternative to malloc() by allocating from a set * of memory pools of various sizes. When mem_malloc is called, an element of * the smallest pool that can provide the length needed is returned. * To use this, MEMP_USE_CUSTOM_POOLS also has to be enabled. */ #ifndef MEM_USE_POOLS #define MEM_USE_POOLS 0 #endif /** * MEMP_USE_CUSTOM_POOLS==1: whether to include a user file lwippools.h * that defines additional pools beyond the "standard" ones required * by lwIP. If you set this to 1, you must have lwippools.h in your * inlude path somewhere. */ #ifndef MEMP_USE_CUSTOM_POOLS #define MEMP_USE_CUSTOM_POOLS 0 #endif
第一种内存分配管理有最小大小的限制,要求请求的分配大小不能小于MIN_SIZE。MIN_SIZE在Mem.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 */
在LwIP初始化函数中,LwIP( )调用mem_init( )
/* Zero the heap and initialize start, end and lowest-free*/ void mem_init(void){ struct mem *mem; ... ... } /** * 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 alignes. */ struct mem { /** index (-> ram[next]) of the next struct */ mem_size_t next; /** index (-> ram[next]) of the next struct */ mem_size_t prev; /** 1: this area is used; 0: this area is unused */ u8_t used; };
以上写的参考了http://bbs.eeworld.com.cn/thread-212023-1-3.html和老衲五木的《LwIP协议栈源码详解》。
http://blog.csdn.net/kaka11/article/details/6198582
因为lwIP主要用于嵌入式系统,内存要求比较高,所以要对那些小对象进行池化之类的处理来加快分配速度,减少内存碎片产生。
lwIP中主要有mem.h, mem.c, memp.h, memp.c, memp_std.h, lwippools.h 几个类组成了内存管理模块。
memp.c
动态内存池管理器, lwip拥有各种不同的内存池来为各个模块的小对象分配内存。
一个内存池主要有name,description,number(内存池里的内存节点的数目)和size(内存池里的内存节点的大小)
内存节点的struct描述:
struct memp { struct memp *next; // 指向下一个内存节点的指针 #if MEMP_OVERFLOW_CHECK // 如果进行内存溢出检测, const char *file; // 发生溢出时调用函数的文件名 int line; // 发生溢出时调用函数的行号 #endif /* MEMP_OVERFLOW_CHECK */ };
lwip中各类内存池的描述在memp_std.h文件中:
该文件主要由三种内存池组成:
1. LWIP_MEMPOOL(标准的内存池)
2. LWIP_MALLOC_MEMPOOL(被mem.c中mem_malloc使用的内存池,需要在lwippools.h自定义不同大小的内存池,稍后会讲到)
3. LWIP_PBUF_MEMPOOL(PBUF的内存池)。
其中2,3两种内存池均是通过调用第一种内存池来实现的,所以我们来看下第一种内存池,也就是lwip的标准内存池。
我们来看一个TCP_PCB的内存池定义:
LWIP_MEMPOOL(TCP_PCB, MEMP_NUM_TCP_PCB, sizeof(struct tcp_pcb), "TCP_PCB")
其中TCP_PCB是内存池名称,
MEMP_NUM_TCP_PCB是节点的数目,
sizeof(struct tcp_pcb)是每个节点大小,
"TCP_PCB"是内存池的描述。
而在memp.c中通过不断定义这些描述(宏)来保存内存池中各种不同的信息到相应的结构中去:
1. 通过各种内存池的唯一的名称定义一个enum,并且在最后插入MEMP_MAX来得到内存池的总数。
typedef enum { #define LWIP_MEMPOOL(name,num,size,desc) MEMP_##name, #include "lwip/memp_std.h" MEMP_MAX } memp_t;
2.定义数组memp_size[MEMP_MAX]存放每个内存池的节点大小。
/** 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" };
3. 定义数组memp_num[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" };
4. 定义数组memp_desc[MEMP_MAX]存放每个内存池的描述。
/** This array holds a textual description of each pool. */ #ifdef LWIP_DEBUG static const char *memp_desc[MEMP_MAX] = { #define LWIP_MEMPOOL(name,num,size,desc) (desc), #include "lwip/memp_std.h" }; #endif /* LWIP_DEBUG */
5. 定义数组memp_memory,这个数组所占有的内存就是所有内存池用的实际内存块。
数组长度为各个池的需要的内存总和,即每个内存池+ ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ),
其中num为节点数目,MEMP_SIZE为每个节点结构所需要的额外内存,size为内存池提供给上层用户的内存大小。
这些大小都是要对齐的,还有个MEM_ALIGNMENT - 1是为了对齐数组memp_memory,
因为定义的memp_memory是不一定对齐的,最坏的情况就要MEM_ALIGNMENT - 1。
/** This is the actual memory used by the pools. */ static u8_t memp_memory[MEM_ALIGNMENT - 1 #define LWIP_MEMPOOL(name,num,size,desc) + ( (num) * (MEMP_SIZE + MEMP_ALIGN_SIZE(size) ) ) #include "lwip/memp_std.h" ];
内存对齐的概念我想大家都懂,这儿就不多做解释了,在lwip的mem.h头文件定义了下面两个宏来进行size和内存地址的对齐。
#ifndef LWIP_MEM_ALIGN_SIZE #define LWIP_MEM_ALIGN_SIZE(size) (((size) + MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) #endif #ifndef LWIP_MEM_ALIGN #define LWIP_MEM_ALIGN(addr) ((void *)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) & ~(mem_ptr_t)(MEM_ALIGNMENT-1))) #endif
mem.c:
如果使用pool的话就是运用内存池管理器进行内存管理。:: 动态内存池(Pool)分配策略
否则的话主要实现了一个实现了一个类似于C malloc的heap的轻量级内存管理器。:: 动态内存堆(Heap)分配策略
动态内存堆(Heap)分配策略 <Static ARRAY> <MEM_LIBC_MALLOC==1, MEM_USE_POOLS==0
>
动态内存池(Pool)分配策略<Static ARRAY> <MEM_LIBC_MALLOC==1, MEM_USE_POOLS==1
>
下面开始讲述每个函数的功能,工作原理和要点:
memp.h memp.c
memp_init(): 初始化每个内存池,通过struct memp作为节点以单链表的形式串联起来。
memp_malloc(): 从相应的内存池中取出内存。
memp_free(): 归还内存到相应的内存池,需要检测溢出。
memp_overflow_init(): 溢出检测的初始化,主要是在用户申请的内存区域前后插入一些填充符0xcd。
memp_overflow_check_element(): 节点溢出检测,在用户申请的内存区域前后检查填充符0xcd是否被覆盖,是则溢出。
memp_overflow_check_all(): 所有节点溢出检测,安全,但是相对慢。
一个内存池的一个结点的内存分配情况:
------------------------------------------------------------------------------------------------------------------------------------
struct memp所占用的内存 + check_overflow_before_region + 用户申请的内存 +check_overflow_after_region
------------------------------------------------------------------------------------------------------------------------------------
memp_memory的内存分配情况:
------------------------------------------------------------------------------------------------------------------------------------
对齐地址的内存空间(0->MEM_ALIGNMENT - 1) + 各个内存池所占内存
------------------------------------------------------------------------------------------------------------------------------------
memp_std.h:
防止多次定义错误,因为memp.c使用#include memp_std.h并且定义以下的宏的技巧,所以每次需要undef这些宏.
mem.h mem.c
#if MEM_USE_POOLS:
mem_malloc: 从相应的提供给malloc用的不同size的pool中取一个合适的一个,并且将这个pool的size保存到相应的结构memp_malloc_helper中。
可以在lwippools.h自定义pool,详情请见代码memp_std.h和memp.h文件的注释:
LWIP_MALLOC_MEMPOOL_START
LWIP_MALLOC_MEMPOOL(20, 256)
LWIP_MALLOC_MEMPOOL(10, 512)
LWIP_MALLOC_MEMPOOL(5, 1512)
LWIP_MALLOC_MEMPOOL_END
mem_free: 释放到相应的内存池中, 取出memp_malloc_helper中的size放入相应的内存池中去。
#else /* MEM_USE_POOLS: */
实现了一个类似于C malloc的heap的轻量级内存管理器。
/* 采用索引双链表的形式来管理heap */ /* 节点结构 */ struct mem { /** index (-> ram[next]) of the next struct */ mem_size_t next; // 下一个struct的索引 /** index (-> ram[next]) of the next struct */ mem_size_t prev; // 上一个struct的索引 /** 1: this area is used; 0: this area is unused */ u8_t used; // 是否被使用 };
mem_init: 初始化heap,并且设置lfree为最低地址的空闲节点,以加快搜索速度。
mem_malloc: 从heap上分配用户所需size的内存。从lfree节点开始搜索空闲并且可以容纳SIZEOF_STRUCT_MEM + size的空间,
如果找到这样的节点mem,则分为两种情况,
如果可容纳的空间可以容纳SIZEOF_STRUCT_MEM + size + (SIZEOF_STRUCT_MEM + MIN_SIZE_ALIGNED),则说明可以新建一个空闲节点,
于是将建立新的空闲节点并且插入到mem和mem->next之间,将mem的used标志为1,
否则的话不建立节点,只是设置mem的used标志为1。
mem_free: 释放的时候会改used标志为0,表示空闲,并且调用plug_holes()函数来进行前后合并空闲空间。
mem_calloc: 使用mem_malloc申请size×count大小的地址,并且初始化清0所分配的内存。
mem_realloc: 重新分配new_size的内存,lwip目前不支持扩大size的情况。
如果当前节点后面的那个节点也是free的话,那么可以合并多余剩下的节点和后面的那个free节点。
如果不是空闲的则看看剩余的空间是否足够新建一个空闲节点,能则建之,并将其插入到链表中去。