lwip-mem_init和mem_malloc详解

合集下载

lwip内存分配算法

lwip内存分配算法

lwIP内存分配算法lwIP(lightweight IP)是一个轻量级的开源TCP/IP协议栈,适用于嵌入式系统。

在lwIP中,内存分配算法是一个重要的部分,它决定了系统的性能和稳定性。

本文将详细介绍lwIP内存分配算法的原理和实现。

1. 内存管理的重要性在嵌入式系统中,内存资源通常非常有限。

因此,有效地管理内存是至关重要的。

lwIP作为一个轻量级的协议栈,需要在有限的内存资源下实现TCP/IP协议的各种功能。

为了提高内存的利用率和系统的性能,lwIP采用了一些特殊的内存分配算法。

2. 内存池管理lwIP使用了内存池管理的方式来分配和管理内存。

内存池是一个预先分配好的内存区域,被划分为多个大小相等的内存块。

每个内存块的大小是固定的,通常是2的幂次方。

内存池的大小和内存块的大小可以根据系统需求进行调整。

内存池管理的优点是可以提高内存分配的效率和降低内存碎片。

由于内存块的大小是固定的,分配一块内存只需要简单地从内存池中取出一个内存块,不需要进行复杂的内存搜索和分配算法。

而且,释放内存也非常简单,只需要将内存块放回内存池即可。

3. 内存分配算法在lwIP中,有两种主要的内存分配算法:固定大小分配算法和动态大小分配算法。

3.1 固定大小分配算法固定大小分配算法是指将内存池划分为多个固定大小的内存块。

每个内存块都有相同的大小,通常是2的幂次方。

这种算法适用于需要频繁分配和释放大小相同的内存的场景。

固定大小分配算法的实现非常简单。

首先,将内存池划分为多个大小相等的内存块。

然后,使用一个位图来标记每个内存块的使用情况。

当分配内存时,从位图中找到一个未被使用的内存块,并标记为已使用。

当释放内存时,将对应的位图标记为未使用。

固定大小分配算法的优点是内存分配和释放非常高效,不会产生内存碎片。

但是,它对于不同大小的内存需求无法很好地支持,且存在内存浪费的问题。

3.2 动态大小分配算法动态大小分配算法是指根据内存需求的大小动态地分配内存。

lwip内存分配算法 -回复

lwip内存分配算法 -回复

lwip内存分配算法-回复LWIP(Lightweight IP)是一个嵌入式系统中的轻量级的网络协议栈。

它主要用于资源受限的系统,如小型微控制器、嵌入式系统和嵌入式操作系统。

LWIP不仅提供了TCP/IP协议栈的功能,而且还采用了一种特殊的内存分配算法来管理堆上的内存。

本文将详细介绍LWIP的内存分配算法。

LWIP的内存分配算法主要包括两个部分:内存池管理和动态内存管理。

其中,内存池管理用于事先规划和分配一块固定大小的内存池,而动态内存管理用于在程序运行时动态地分配和释放内存空间。

首先,我们来看内存池管理。

内存池管理是通过将内存划分为一组固定大小的内存块,然后将这些内存块存放到一个内存池中,以便在需要时可以快速地分配给应用程序。

具体来说,LWIP将内存划分为不同大小的内存块,这取决于应用程序对内存的需求。

每个内存块都保存着一个链表指针,用于将已分配的内存块连接起来。

当应用程序需要分配内存时,LWIP会遍历内存池中的内存块链表,找到一个大小合适的内存块来分配。

如果找到了一个可用的内存块,LWIP将该内存块从链表中移除,并返回给应用程序使用。

如果没有找到大小合适的内存块,LWIP将会分配一块更大的内存块,并将其划分为多个较小的内存块,其中一个分配给应用程序使用,而其他的内存块则重新加入到内存块链表中。

另一方面,当应用程序释放内存时,LWIP会将该内存块重新加入到内存块链表中,以便在下次分配内存时可以重新使用。

这样,在程序运行时,LWIP可以避免频繁地向操作系统请求内存空间,从而提高了内存的利用率和系统性能。

接下来,我们来看动态内存管理。

动态内存管理是指在程序运行时根据需求动态地分配和释放内存空间。

LWIP使用了一套高效的动态内存管理算法来实现这一功能。

具体来说,LWIP会维护一张内存分区表,用于记录系统中所有已分配的内存区域和大小。

当应用程序需要分配内存时,LWIP会遍历内存分区表,找到一个大小合适且未使用的内存区域来分配。

LWIP+UCOSIII学习笔记

LWIP+UCOSIII学习笔记

1.网络芯片比较目前使用的网络芯片一般有以下几种:DP83848、DM9000、enc28j60、RLD8019、w5100网卡工作在osi的最后两层,物理层(PHY)和数据链路层(MAC)。

物理层定义了数据传送与接收所需要的电与光信号、线路状态、时钟基准、数据编码和电路等,并向数据链路层设备提供标准接口。

物理层的芯片称之为PHY。

数据链路层则提供寻址机构、数据帧的构建、数据差错检查、传送控制、向网络层提供标准的数据接口等功能。

以太网卡中数据链路层的芯片称之为MAC 控制器。

1.DP83848:物理层(PHY),跟MII接口。

2. DM9000:物理层(PHY)和数据链路层(MAC)(10/100M)。

跟8/16/32总线接口3. enc28j60:MAC+PHY(10M Base T)。

spi接口4. w5100:硬件TCP/IP协议栈+MAC+PHY(10/100M Base T)。

并行总线接口5. RLD8019:和w5100类似,比较老。

举个例子:W5100里面用硬件逻辑电路实现了TCP/IP的协议栈结构,不需要向ENC28J60这样的网络控制器那样还需要一个资源较大的MCU跑软件协议栈。

你直接把W5100当外部RAM使用,MCU初始化一下I/O,寄存器等就能使用了。

2.TCP/IP协议族的四个层次网络协议通常分不同层次进行开发,每一层分别负责不同的通信功能。

一个协议族,比如TCP/IP,是一组不同层次上的多个协议的组合。

TCP/IP通常被认为是一个四层协议系统,如下图所示:每一层负责不同的功能:1) 链路层,有时也称作数据链路层或网络接口层,通常包括操作系统中的设备驱动程序和计算机中对应的网络接口卡。

它们一起处理与电缆(或其他任何传输媒介)的物理接口细节。

2) 网络层,有时也称作互联网层,处理分组在网络中的活动,例如分组的选路。

在TCP/IP协议族中,网络层协议包括I P协议(网际协议),ICMP协议(Internet互联网控制报文协议),以及IGMP协议(Internet组管理协议)。

lwip内存分配算法

lwip内存分配算法

lwIP内存分配算法lwIP(Lightweight IP)是一个轻量级的开源TCP/IP协议栈,它专为嵌入式系统设计,具有较小的内存占用和高度可配置性。

在lwIP中,内存的分配和管理是一个重要的问题,因为嵌入式系统通常具有有限的资源。

内存管理问题在网络通信中,数据包的传输需要使用缓冲区来存储数据。

而在lwIP中,内存分配算法主要用于管理缓冲区的分配和释放。

由于嵌入式系统资源有限,因此需要设计一种高效的内存管理算法来满足系统对内存资源的需求。

lwIP提供了两种主要的内存管理方式:静态内存管理和动态内存管理。

静态内存管理静态内存管理是指在编译时就确定了系统所需的所有缓冲区,并将其固定分配给lwIP。

这种方式可以确保系统在运行时不会发生动态分配失败的情况。

静态内存管理适用于对资源要求严格、对性能要求不高、并且可以预先估计所需资源量的场景。

静态内存管理需要事先配置好每个模块所需的缓冲区大小,并通过修改lwipopts.h文件中相关宏定义来实现。

例如,可以通过修改MEMP_NUM_PBUF来指定pbuf结构体的数量,通过修改PBUF_POOL_SIZE来指定pbuf pool的大小。

静态内存管理的优点是简单、高效,不需要运行时的内存分配和释放操作。

然而,它的缺点是资源利用率较低,不能动态适应系统运行时的需求变化。

动态内存管理动态内存管理是指在运行时根据需要动态地分配和释放缓冲区。

这种方式可以有效地提高资源利用率,并且可以适应系统运行时需求的变化。

但是,动态内存管理也带来了一些额外的开销和复杂性。

lwIP中使用了两种动态内存管理算法:堆内存管理和池式内存管理。

堆内存管理堆内存管理是使用标准C库函数(如malloc和free)来进行动态内存分配和释放。

在lwIP中,默认情况下使用堆内存管理算法。

堆内存管理需要在系统初始化时调用mem_init()函数来初始化堆,并通过修改lwipopts.h文件中相关宏定义来配置堆的大小。

lwip中各种函数,标志位的总结

lwip中各种函数,标志位的总结

mem_init( ) 内存堆的初始化函数,主要是告知内存堆的起止地址,以及初始化空闲表,由lwip 初始化时自己调用,该接口为内部私有接口,不对用户层开放mem_malloc( ) 申请分配内存。

将总共需要的字节数作为参数传递给该函数,返回值是指向最新分配的内存的指针,而如果内存没有分配好,则返回值是NULLmem_calloc( ) 是对mem_malloc( )函数的简单包装,他有两个参数,分别为元素的数目和每个元素的大小,这两个参数的乘积就是要分配的内存空间的大小,与mem_malloc()不同的是它会把动态分配的内存清零。

有经验的程序员更喜欢使用mem_ calloc (),memp_num:这个静态数组用于保存各种类型缓冲池的成员数目memp_sizes:这个静态数组用于保存各种类型缓冲池的结构大小memp_tab:这个指针数组用于指向各种类型缓冲池当前空闲节点memp_init():内存池的初始化,主要是为每种内存池建立链表memp_tab,其链表是逆序的,此外,如果有统计功能使能的话,也把记录了各种内存池的数目。

memp_malloc():如果相应的memp_tab链表还有空闲的节点,则从中切出一个节点返回,否则返回空。

memp_free()把释放的节点添加到相应的链表memp_tab头上。

系统是调用内存堆分配函数mem_malloc进行内存分配的。

分配空间的大小包括pbuf结构头大小SIZEOF_STRUCT_PBUF,需要的数据存储空间大小length,还有一个offset系统是调用内存堆分配函数mem_malloc进行内存分配的。

段区域的offset的大小,这段区域用来存储数据的包头,如TCP包头,IP包头等pbuf_free(A)函数来删除pbuf结构PBUF_POOL 类型和PBUF_ROM类型、PBUF_REF类型需要通过memp_free()函数删除,PBUF_RAM类型需要通过mem_free()函数删除memp_memory是缓冲池的起始地址,前面已有所讨论;MEMP_MAX是POOL 类型数; memp_tab 用于指向某类POOL 空闲链表的起始节点;memp_num表示各种类型POOL的个数;memp_sizes表示各种类型单个POOL的大小,对于MEMP_PBUF_POOL和MEMP_PBUF型的POOL,其大小是pbuf 头和pbuf可装载数据大小的总和。

LWIP内存管理知识汇总

LWIP内存管理知识汇总

LWIP内存管理知识汇总
一 LWIP内存管理
LWIP的内存管理使用了2种方式:内存池memp和内存堆mem,如图1所示。

内存池的特点是预先开辟多组固定大小的内存块组织成链表,实现简单,分配和回收速度快,不会产生内存碎片,但是大小固定,并且需要预估算准确。

内存堆的本质是对一个事先定义好的内存块进行合理有效的组织和管理,主要用于任意大小的内存分配,实现较复杂,分配需要查找,回收需要合并,容易产生内存碎片,需要合理估算内存堆的总大小。

图1内存池与内存堆
1. 数据包管理
数据包管理结构pbuf共有四种类型,它们的特点和使用场合如表1所示。

表1 pbuf类型与特点
每一种pbuf分配内存的方式都不一样,如图2所示。

图2四种数据包管理结构
只有选择合适的pbuf类型才能发挥LWIP的最大性能,一个数据包可能是多种pbuf的组合,用链表连接起来,如图3所示。

图3 pbuf链表
2. 设置内存大小
为LWIP开辟一个专用的内存堆是应该的,这样一来LWIP的mem_alloc()和mem_free()都将基于该堆内存进行分配和回收,不影响其他系统内存的使用。

如图1左所示,lwipopt.h 文件中宏MEM_SIZE定义了堆区的大小,对于一个负荷较重的系统堆区需要分配较大。

lwip_mempool实现方法

lwip_mempool实现方法

lwIP是一个轻量级的开源TCP/IP协议栈,广泛应用于嵌入式系统中。

在lwIP中,mempool是一个非常重要的模块,它用于内存池的管理和分配。

本文将介绍lwIP中mempool的实现方法,希望能够对读者有所帮助。

1. mempool的概念和作用mempool是memory pool的缩写,它的作用是管理系统中的内存资源,提供内存的分配和释放功能。

在lwIP中,mempool用于管理网络数据包的内存分配,以及协议栈中各种数据结构的内存分配。

通过mempool,可以提高内存的复用率,减少内存碎片,提高系统的性能和稳定性。

2. lwIP中mempool的结构在lwIP中,mempool的结构主要由两部分组成,分别是memp和memp_desc。

其中,memp代表内存池,它管理着一块连续的内存空间;memp_desc则代表内存块的描述信息,用于记录内存块的分配状态和其他相关信息。

3. memp和memp_desc的初始化在lwIP中,memp和memp_desc的初始化是非常关键的。

需要通过宏定义来指定mempool的大小和内存块的大小。

在系统初始化的过程中,需要调用相应的函数来初始化memp和memp_desc。

在初始化过程中,需要考虑到内存池的大小和内存块的大小,以及内存池的分配策略等因素,确保内存池的有效管理和高效利用。

4. memp的分配和释放在lwIP中,memp的分配和释放是通过宏定义的函数来实现的。

通过宏定义的函数,可以实现对内存池的高效管理和灵活利用。

在分配内存时,需要考虑内存池的状态和内存块的状态,确保内存的有效分配;在释放内存时,需要及时回收内存,避免内存泄漏和内存碎片的产生。

5. memp_desc的管理和维护在lwIP中,memp_desc的管理和维护也是非常重要的。

通过memp_desc,可以实现对内存块的状态和使用情况的记录,确保内存的有效管理和高效利用。

在memp_desc的管理和维护过程中,需要考虑内存块的状态和分配情况,及时更新内存块的信息,确保内存池的状态和内存块的状态能够及时反映系统的实际情况。

LwIP协议详解

LwIP协议详解
其次是实现与信号量和邮箱操作相关的函数,比如建立、删除、等待、释放等。如果 在裸机上直接跑 LWIP,这点实现起来比较麻烦,使用者必须自己去建立一套信号量和邮箱 相关的机制。一般情况下,在使用 LWIP 的嵌入式系统中都会有操作系统的支持,而在操作 系统中信号量和邮箱往往是最基本的进程通信机制了。UC/OSII 应该算是最简单的嵌入式操 作系统了吧,它也无例外的能够提供信号量和邮箱机制,只要我们将 UC/OSII 中的相关函 数做相应的封装,就可满足 LWIP 的需求。LWIP 使用邮箱和信号量来实现上层应用与协议 栈间、下层硬件驱动与协议栈间的信息交互。LWIP 协议模拟了 TCP/IP 协议的分层思想, 表面上看 LWIP 也是有分层思想的,但从实现上看,LWIP 只在一个进程内实现了各个层次 的所有工作。具体如下:LWIP 完成相关初始化后,会阻塞在一个邮箱上,等待接收数据进 行处理。这个邮箱内的数据可能来自底层硬件驱动接收到的数据包,也可能来自应用程序。 当在该邮箱内取得数据后,LWIP 会对数据进行解析,然后再依次调用协议栈内部上层相关 处理函数处理数据。处理结束后,LWIP 继续阻塞在邮箱上等待下一批数据。当然 LWIP 还 有一大串的内存管理机制用以避免在各层间交互数据时大量的时间和内存开销,这将在后续 讲解中慢慢道来。当然,但这样的设计使得代码理解难度加大,这一点让人头大。信号量也
我想我很适合当一个歌颂者,青春在风中飘着。你知道,就算大雨让这座城市颠倒,我 会给你怀抱;受不了,看见你背影来到,写下我度秒如年难捱的离骚;就算整个世界被寂寞 绑票,我也不会奔跑;逃不了,最后谁也都苍老,写下我,时间和琴声交错的城堡。我正在 听的歌。扯远了…
正题,嵌入式产品连入 Internet 网,这个 MS 是个愈演愈烈的趋势。想想,你可以足不 出户对你的产品进行配置,并获取你关心的数据信息,多好。这也许也是物联网世界最基本 的雏形。当然,你的产品要有如此功能,那可不容易,至少它得有个目前很 Fashion 的 TCP/IP 协议栈。LWIP 是一套用于嵌入式系统的开放源代码 TCP/IP 协议栈。在你的嵌入式处理器 不是很 NB,内部 Flash 和 Ram 不是很强大的情况下,用它还是很合适滴。
  1. 1、下载文档前请自行甄别文档内容的完整性,平台不提供额外的编辑、内容补充、找答案等附加服务。
  2. 2、"仅部分预览"的文档,不可在线预览部分如存在完整性等问题,可反馈申请退款(可完整预览的文档不适用该条件!)。
  3. 3、如文档侵犯您的权益,请联系客服反馈,我们会尽快为您处理(人工客服工作时间:9:00-18:30)。

lwip-mem_init和mem_malloc详解[cpp] view plain copy <pre name="code"class="cpp">#define MEM_ALIGNMENT 4//对齐方式为4字节对齐#ifndef LWIP_MEM_ALIGN_SIZE #define LWIP_MEM_ALIGN_SIZE(size) (((size) +MEM_ALIGNMENT - 1) & ~(MEM_ALIGNMENT-1)) //实现待分配数据空间的内存对齐#endif #ifndef LWIP_MEM_ALIGN //地址对齐,对齐方式也为4字节对齐#define LWIP_MEM_ALIGN(addr) ((void*)(((mem_ptr_t)(addr) + MEM_ALIGNMENT - 1) &~(mem_ptr_t)(MEM_ALIGNMENT-1))) #endif /* MEM_SIZE: the size of the heap memory. If the application will send a lot of data that needs to be copied, this should be set high. */ #define MEM_SIZE (8*1024) //堆的总空间大小,此后在这个基础上划分堆,将在这个空间进行内存分配,内存块结构体和数据都是在这个空间上的//mem为内存块的结构体,next;,prev都为内存块索引struct mem { /** index (-> ram[next]) of the next struct *///ram为堆的首地址,相当于数组的首地址,索引基地址mem_size_t next; //next为下一个内存块的索引/** index (-> ram[next]) of the next struct */mem_size_t prev; //prev为前一个内存块的索引/** 1: this area is used; 0: this area is unused */ u8_t used;//标志此内存块已被分配}; static struct mem *ram_end; /** 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 //内存块大小的最小限制,不能小于12 #endif /* MIN_SIZE */ /* some alignment macros: we define them here for better source code layout */ #define MIN_SIZE_ALIGNEDLWIP_MEM_ALIGN_SIZE(MIN_SIZE) //将MIN_SIZE按4字节对齐,即把12按4字节对齐#defineSIZEOF_STRUCT_MEMLWIP_MEM_ALIGN_SIZE(sizeof(struct mem)) //将mem大小按4字节对齐#define MEM_SIZE_ALIGNEDLWIP_MEM_ALIGN_SIZE(MEM_SIZE) //将堆的总空间按4字节对齐,MEM_SIZE在前面,为8*1024 //内存对齐解释看我的博文:/lg2lh/article/details/34853883 /** the heap. we need one struct mem at the end and some room foralignment */ static u8_t ram_heap[MEM_SIZE_ALIGNED + (2*SIZEOF_STRUCT_MEM) + MEM_ALIGNMENT]; //实际开的堆内存空间,MEM_SIZE_ALIGNED为对齐后的数据空间为8192 //堆内存的大小为MEM_SIZE_ALIGNED+(2*SIZEOF_STRUCT_MEM)+MEM _ALIGNMENT=8192+2*MEN结构体的大小+4 void mem_init(void) { struct mem *mem; //定义一个mem 结构体指针变量LWIP_ASSERT("Sanity check alignment", (SIZEOF_STRUCT_MEM &(MEM_ALIGNMENT-1)) == 0); /* align the heap */ram = LWIP_MEM_ALIGN(ram_heap); //将堆空间首地址ram_heap按4字节地址对齐/* initialize the start of the heap */ mem = (struct mem *)ram; //将堆空间ram 首地址强制转换成mem结构体类型,作为首个内存块,但这个内存块还未使用mem->next =MEM_SIZE_ALIGNED; //把首个内存块的next指针指向了堆空间的最后一个地址(MEM_SIZE_ALIGNED为8*1024),后面实际在mem_malloc时会动态调整next索引, //从而得到实际分配内存空间即为mem->next减去该内存块mem 的地址//待分配内存块的next索引总是指向堆空间最后,好像也不一定,但是按照思路是这样的。

mem->prev = 0; //初始化,因为是第一个内存块,所以前一个内存块不存在,故初始化为0 mem->used = 0; //该内存块没有被分配,待分配状态/* initialize the end of the heap */ram_end = (struct mem *)&ram[MEM_SIZE_ALIGNED]; //例化一个堆空间末尾内存块,该内存块指向最后一个地址,标志结尾用的已被分配,不可再分配了ram_end->used = 1; //该内存块已被分配ram_end->next = MEM_SIZE_ALIGNED; //因为后续再无内存块故,next索引指向最后,即自己ram_end->prev = MEM_SIZE_ALIGNED; //这个我也不知道啊mem_sem = sys_sem_new(1); /* initialize the lowest-free pointer to the start of the heap */ lfree = (struct mem *)ram; //初始化空闲对指针,此时首个内存块是空闲的MEM_STATS_AV AIL(avail,MEM_SIZE_ALIGNED); } void *mem_malloc(mem_size_t size) { mem_size_t ptr, ptr2; struct mem *mem, *mem2; #ifLWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXTu8_t local_mem_free_count = 0; #endif /*LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ LWIP_MEM_ALLOC_DECL_PROTECT(); if (size == 0) { return NULL; } //size为0的话返回null 分配不成功/* Expand the size of the allocated memoryregion so that we can adjust for alignment. */ size = LWIP_MEM_ALIGN_SIZE(size); //将待分配数据按4字节进行对齐if(size < MIN_SIZE_ALIGNED) { //如果待分配空间小于MIN_SIZE_ALIGNED(12),则返回分配空间也要为12,最小分配空间为12 /* every data block must be at least MIN_SIZE_ALIGNED long */ size = MIN_SIZE_ALIGNED; } if (size >MEM_SIZE_ALIGNED) { //如果待分配空间大于MEM_SIZE_ALIGNED(8*1024),超出堆空间,则返回NULL,无法分配return NULL; } /* protect the heap from concurrent access */sys_arch_sem_wait(mem_sem, 0);LWIP_MEM_ALLOC_PROTECT(); //未定义#ifLWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT/* run as long as a mem_free disturbed mem_malloc */ do { local_mem_free_count = 0; #endif /*LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ /* Scan through the heap searching for a free block that is big enough, * beginning with the lowest free block. */ //ptr初值=空闲内存块地址与堆内存首地址之差,如果ptr+size小于堆空间总大小8*1024,则可实现相应大小//的内存块分配,其中ptr实际为已分配了的空间大小,size为待分配的空间大小,两个和一定要小于总空间,才可以实现分配. //判断完成后,将ptr赋值为该内存块next所指地址for (ptr = (u8_t *)lfree - ram; ptr <MEM_SIZE_ALIGNED - size; ptr = ((struct mem *)&ram[ptr])->next) { //将待分配的这个内存空间初始化为内存块结构体mem = (struct mem *)&ram[ptr]; #ifLWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT //未定义mem_free_count = 0;LWIP_MEM_ALLOC_UNPROTECT(); /* allow mem_free to run */LWIP_MEM_ALLOC_PROTECT(); if(mem_free_count != 0) { local_mem_free_count = mem_free_count; } mem_free_count = 0;#endif /*LWIP_ALLOW_MEM_FREE_FROM_OTHER_CONTEXT */ //ptr为已分配了的内存空间//后面你会发现,待分配内存块的mem->next始终指向堆空间的最后,即MEM_SIZE_ALIGNED。

相关文档
最新文档