LWIP内存占用与裁剪
工具链:GCC
LWIP版本:2.0.2 默认配置
静态内存总体分布
网络相关内存占用主要分为三个部分,其中LWIP内存池占主要部分
DNS解析
LWIP内存池
RTT相关
DNS占用
DNS的内存占用在整个协议栈中的比重不大,仅1k左右。
DNS tab数组占用内存较多,如果应用中同时进行dns解析的场景较少,可适当较少DNS tab数量。可设置DNS_TABLE_SIZE=2。
DNS_MAX_NAME_LENGTH表示能够解析最大的DNS名字长度
MEMPOOL内存占用
LWIP内存占用主要在MEMPOOL这一块。通过提前开辟静态数组,来提高LWIP分配各种描述符内存的速度。静态内存总共分配42715字节,41K。
其中各种描述符分配了大约12202字节数据,静态内存池分配了25731字节数据。
描述符中 PBUF和ARP_QUEUE占用内存较多,静态分配了4510字节内存,这两个描述符可根据具体情况作出相应的调整
除去PBUF和ARP_QUEUE这两个描述符,其他描述符占用7692字节内存。
LWIP静态内存池占用大量内存,且使用较少,PBUF与ARP_QUEUE占用一部分内存,可做适当裁剪,通信相关的描述符,占用较少内存,7K左右。
单个大小 = (大小 + 1 - 4) / 数量
RTT相关占用
RTT静态内存总共占用2464字节,主要是用于启动rx,rx线程。当没有使用到这两个线程的时候,可以移除。
动态内存分配
初始化分配
系统启动时,会动态创建一个tcpip线程,需要消耗1172字节内存
会为tcpip线程创建一个邮箱,需要消耗80字节内存
会为tcpip线程创建一个互斥量,需要消耗36字节内存
创建连接分配
建立一个连接需要创建一个fd,消耗32字节内存
需要创建一个邮箱,消耗88字节内存
需要创建一个信号量,消耗32字节内存
还需要创建socket,netconn,pcb描述符等,这些占用静态内存
数据通信分配
发送数据时,需要动态分配pbuf缓存数据
接收数据时,需要动态分配pbuf缓存数据
发送TCP协议数据,需要TCP_SEG描述符,一包数据可能会占用多个TCP_SEG描述符
接收tcp协议数据,需要TCPIP_MSG_INPKT描述符
各个描述符的作用
PCB描述符
PCB描述符是用来管理连接协议的,不同的连接协议PCB不相同。PCB描述符有RAW,UDP,TCP,TCP_LISTEN这四种。
RAM描述符用来管理原始数据,直接提供IP报文的访问
UDP描述符用来管理UDP协议数据。
TCP描述符用来管理TCP协议通信数据
TCP_LISTEN描述符用来管理TCP侦听数据
NETCONN描述符
NETCONN描述符是用来管理一个连接,该连接类型可是RAW,UDP,TCP,TCP_LISTEN这四种。
收发数据描述符
收发数据需要描述符的,仅仅是TCP协议。
TCP发送数据时,需要将tcp报文打包,使用TCP_SEG描述符进行管理。
TCP接收数据时,需要将PBUF转换成TCP报文,然后使用TCPIP_MSG_INPKT描述符管理。
其他描述符
ARP_QUEUE,管理ARP数据包
IGMP_GROUP,多播,组播包管理
PBUF,只分配PBUF头部
PBUF_POOL,静态内存池
NETBUF
NETDB
TCPIP_MSG_API
NETDB
静态内存裁剪与影响
lwip最先应该裁剪静态内存池,耗得的内存最多
其次裁剪TCPIP_MSG_INPKT,PBUF等使用较少的描述符
在次裁剪RAW_PCB,UDP_PCB等东西
最后裁剪TCP_SEG,这个值与RT_LWIP_TCP_SND_BUF缓冲区有关,1k的缓冲区大约需要5个seg
发送窗口的大小不易过大,也不宜过小,更具网卡的性能做调整。网卡性能差,则窗口应该小,性能好则窗口大,相应的其他值也应该调大。
初步裁减
裁剪:静态内存占用最多的是内存池,默认配置内存池占用大约24k作用内存,LWIP内核中没有使用这一片内存,如果应用中没有使用这块内存,可以减少这一片内存 RT_LWIP_PBUF_NUM = 2 。可以减少20k的内存。
影响:静态内存池的减少并不会影响LWIP内核的效率,但可能对应用有影响。应用中如果使用了静态内存池,可能会导致内存分配失败。
均衡裁剪
裁剪:在描述符表中,PBUF描述符与ARP_QUEUE描述符占用内存较多,且使用不是特别频繁,可根据实际情况,减少这两种描述符的数据MEMP_NUM_PBUF MEMP_NUM_ARP_QUEUE。如果数量各减少一半,可以减少2k内存
影响:PBUF在LWIP内核中有少数地方在使用,减少PBUF数量可能导致LWIP运行不稳定。
影响:ARP_QUEUE是用来处理ARP请求的,减少ARP_QUEUE可能导致ARP请求失败,导致通信不成功。
极端裁剪
裁剪:可以根据应用情况,合理减少TCP_SEG描述符的数量。实际使用中,如果没有很多个TCP连接,且数据通信频繁或数据量大,可能巅峰时刻也用不完这种描述符。适当调整RT_LWIP_TCP_SEG_NUM的值达到节约内存的目的。如果数量减少一半,可以减少1k内存
裁剪:可以根据应用情况,合理减少PCB描述符及NETCONN的数量。
影响:不建议这种裁剪,除非极端缺少内存,而且裁剪也省不了多少内存,顶天2k,而且可能导致出现乱七八糟的问题。
其他
这部分不涉及内存裁剪相关的内容,介绍下RT_LWIP_TCP_SND_BUF RT_LWIP_TCP_WND这两个参数
RT_LWIP_TCP_SND_BUF:TCP发送缓冲区大小。首先这个缓冲区不会分配实际的内存。
RT_LWIP_TCP_WND:TCP发送窗口大小,当网络性能较弱时,应该适当调小发送窗口大小。
ifconfig参数的作用
RT_LWIP_UDP 使能UDP功能
RT_LWIP_TCP 使能TCP功能
RT_LWIP_RAW 使能RAM功能
RT_MEMP_NUM_NETCONN 8 最大连接数量
RT_LWIP_PBUF_NUM 16 静态内存池数量
RT_LWIP_RAW_PCB_NUM 4 RAW_PCB描述符数量
RT_LWIP_UDP_PCB_NUM 4 UDP_PCB描述符数量
RT_LWIP_TCP_PCB_NUM 4 TCP_PCB描述符数量
RT_LWIP_TCP_SEG_NUM 40 TCP发送数据描述符数量
RT_LWIP_TCP_SND_BUF 8196 缓存区大小
RT_LWIP_TCP_WND 2048 窗口大小
RT_LWIP_TCPTHREAD_PRIORITY 10 TCPIP线程优先级
RT_LWIP_TCPTHREAD_MBOX_SIZE 8 邮箱数据,同一时间能够接收的pbuf包
RT_LWIP_TCPTHREAD_STACKSIZE 1024 TCPIP线程栈大小
RT_LWIP_ETHTHREAD_PRIORITY 12 rx/tx发送线程优先级
RT_LWIP_ETHTHREAD_STACKSIZE 1024 rx/tx栈大小
RT_LWIP_ETHTHREAD_MBOX_SIZE 8 rx/tx邮箱数量
附录
各描述符大小
单个大小计算=(大小+1-4)/数量
PBUF_POOL 单个大小 1608
打印的原始数据如下,第一列数字是sizeof(memp_memory_RAW_PCB_base)描述符总共占的内存,第二列是实际使用的内存(总内存 + 1 - 4)
memp_memory_RAW_PCB_base 75 72
memp_memory_UDP_PCB_base 155 152
memp_memory_TCP_PCB_base 835 832
memp_memory_TCP_PCB_LISTEN_base 611 608
memp_memory_TCP_SEG_base 1803 1800
memp_memory_NETBUF_base 123 120
memp_memory_NETCONN_base 867 864
memp_memory_TCPIP_MSG_API_base 483 480
memp_memory_TCPIP_MSG_INPKT_base 483 480
memp_memory_ARP_QUEUE_base 1563 1560
memp_memory_SYS_TIMEOUT_base 303 300
memp_memory_NETDB_base 355 352
memp_memory_PBUF_base 739 736
memp_memory_PBUF_POOL_base 12867 12864
各SIZEOF大小
管理一个描述符所占大小
例如raw_pcb,其他的也是这样子计算的。
x = (((sizeof(struct memp)) + 4 - 1U) & ~(4 -1U)) + (((16) + 4 - 1U) & ~(4 -1U))
y = ((((sizeof(struct raw_pcb)) + 4 - 1U) & ~(4 -1U)) + (((16) + 4 - 1U) & ~(4 -1U)))
大小 = (x + y) * 数量
所占空间 = 大小 + 4 - 1U
创建一个连接需要的内存
socket = sizeof(struct lwip_sock)(32) + fd(32) + mb_create(88) + sem_create(32) = 184
netconn = 104
建立tcp客户端连接 = socket + netconn + tcp_pcb(204) = 492
建立tcp服务端连接 = socket + netconn + tcp_pcb_listen(72) = 360
tcp客户端通信 = tcp客户端连接 + 5 * TCP_SEG(60) = 792
tcp服务端通信 = tcp服务端连接 + netconn(104) + tcp_pcb(204) + 2 * tcpip_msg_inpkt(60) = 824
这里只统计了固定内存,或许还有遗漏。
通信过程中各种malloc和free的内存没有统计。LWIP会将发送的数据cp一遍,如发送4k数据,则至少malloc 4k内存拷贝数据,等数据确认发送完毕,则释放内存。
创建一个socket,fd分配的内存,严格来说应该不属于lwip这边的。
LWIP各选项描述
名字 默认值 描述
LWIP_SNMP 0 SNMP协议启用
SNMP_CONCURRENT_REQUESTS 1 SNMP当前允许请求数量
SNMP_TRAP_DESTINATIONS 1 SNMP trap目的地址数目
SNMP_PRIVATE_MIB 1 SNMP 私有节点设置允许
SNMP_SAFE_REQUESTS 1 仅回复SNMP安全请求
SYS_LIGHTWEIGHT_PROT 1 临界中断保护开关(多任务模式下开启)
NO_SYS 0 LWIP独立运行或者基于操作系统,为0则基于操作系统
MEM_LIBC_MALLOC 0 采用LWIP自带函数分配动态内存
MEM_LIBC_MALLOC 0 内存池不通过内存堆来分配
MEM_ALIGNMENT 4 字节对齐(和CPU的位数有关,32位设置为4)
MEM_SIZE 8*1024 堆内存大小,用于发送数据
MEMP_SANITY_CHECK 0 mem_free调用后检查链表是否有循环 by zc
MEMP_OVERFLOW_CHECK 0 lwip堆内存溢出检查
MEM_USE_POOLS 0 内存堆不通过内存池分配
MEM_USE_POOLS_TRY_BIGGER_POOL 0 申请内存失败不选择大内存池
MEMP_USE_CUSTOM_POOLS 0 同上
MEMP_NUM_PBUF 60 来自memp的PBUF_ROM(ROM内存池)和PBUF_REF(RAM内存池)数目最大总和
MEMP_NUM_RAW_PCB 4 RAW连接的PCB数目(需要LWIP RAW有效)
MEMP_NUM_UDP_PCB 4 能够同时连接的UDP的PCB数目
MEMP_NUM_TCP_PCB 4 能够同时连接的TCP的PCB数目
MEMP_NUM_TCP_PCB_LISTEN 1 能够同时监听的TCP的PCB数目
MEMP_NUM_TCP_SEG 40 能够同时在队列里的TCP的PCB数目
MEMP_NUM_REASSDATA 8 最大同时等待重装的IP包数目,是整个IP包,不是IP分片
MEMP_NUM_ARP_QUEUE 30 最大等待回复ARP请求的数目(ARP_QUEUEING有效)
MEMP_NUM_IGMP_GROUP 8 多播组同时接收数据的最大成员数目(LWIP_IGMP有效)
MEMP_NUM_SYS_TIMEOUT 20 能够同时激活的超时连接数目
MEMP_NUM_NETBUF 10 netbufs结构的数目
MEMP_NUM_NETCONN 16 netconns结构的数目
MEMP_NUM_TCPIP_MSG_API 40 tcpip_msg结构的最大数目,用于callback和API的通讯 by zc
MEMP_NUM_TCPIP_MSG_INPKT 40 tcpip_msg接受数据包结构的最大数目 by zc
PBUF_POOL_SIZE 48 内存池数量(小内存减小该选项可大大减小内存占用)
LWIP_ARP 1 ARP协议允许
ARP_TABLE_SIZE 10 ARP维护的表项大小
ARP_QUEUEING 1 硬件地址解析时,将发送数据包计入队列
ETHARP_TRUST_IP_MAC 1 所有IP数据包都会直接引起ARP table的更新,为0则非表项内IP-MAC关系会引起ARP请求
ETHARP_SUPPORT_VLAN 0 非虚拟局域网,为1则仅虚拟局域网通讯有效
IP_FORWARD 0 不允许不匹配数据包转发,多接口时为1
IP_OPTIONS_ALLOWED 1 带IP选项数据包允许 为0则丢弃所有IP数据包
IP_REASSEMBLY 1 允许接收IP包分片包(为0不允许,不能够接收大于MTU的包)
IP_FRAG 1 允许发送IP包分片包
IP_REASS_MAXAGE 3 允许接收的最大分段数
IP_REASS_MAX_PBUFS 10 最大允许存在的IP分片包占用的内存池个数
IP_FRAG_USES_STATIC_BUF 1 IP分片使用静态缓冲区
IP_FRAG_MAX_MTU 1500 IP分片最大缓冲数量
IP_DEFAULT_TTL 255 IP数据包最大经历设备数目
IP_SOF_BROADCAST 0 IP发送广播包过滤
IP_SOF_BROADCAST_RECV 0 IP接收广播包过滤
LWIP_ICMP 1 开启ping包接收/发送
ICMP_TTL (IP_DEFAULT_TTL) ping包最大经历设备数目
LWIP_BROADCAST_PING 0 不回复广播ping包
LWIP_MULTICAST_PING 0 不回复多播ping包
LWIP_RAW 0 无操作系统基于回调函数驱动
RAW_TTL (IP_DEFAULT_TTL) 应用层数据传输次数(基于IP层的TTL)
LWIP_DHCP 0 动态主机协议配置(为1时)
LWIP_AUTOIP 0 动态主机IP地址配置(为1时)
LWIP_DHCP_AUTOIP_COOP 0 允许上述两种配置同时存在于1个接口(为1时)
LWIP_DHCP_AUTOIP_COOP_TRIES 9 DHCP分配允许失败次数,失败则使用AUTOUP
LWIP_IGMP 0 LWIP组管理协议
LWIP_DNS 0 域名服务器模块(依托UDP协议)
DNS_TABLE_SIZE 4 域名服务器维护的最大入口数目
DNS_MAX_NAME_LENGTH 256 域名服务器主机地址最大长度
DNS_MAX_SERVERS 2 域名服务器最大服务数目
DNS_DOES_NAME_CHECK 1 查询域名服务器时检测地址名
DNS_USES_STATIC_BUF 1 域名服务器使用静态地址
DNS_MSG_SIZE 512 域名服务器接收最大通讯数据长度
DNS_LOCAL_HOSTLIST 0 在本地维护域名服务器主机-地址表(为1时)
DNS_LOCAL_HOSTLIST_IS_DYNAMIC 0 主机-地址表实时更新(为1时)
LWIP_UDP 1 启用UDP协议(snmp协议基于此)
LWIP_UDPLITE 1 UDP协议启用精简版
UDP_TTL (IP_DEFAULT_TTL) UDP数据包传输次数
LWIP_NETBUF_RECVINFO 0 接收到的数据包除首个外其它不附加目的地址和端口
LWIP_TCP 1 启用TCP协议(http协议基于此)
TCP_TTL (IP_DEFAULT_TTL) TCP数据包传输次数
TCP_WND 4*TCP_MSS tcp窗口大小
TCP_MAXRTX 12 最大允许重传TCP数据包数目
TCP_SYNMAXRTX 6 最大允许重传SYN连接包数目
TCP_QUEUE_OOSEQ (LWIP_TCP) TCP接收队列外数据块排序
TCP_MSS 1460 tcp报文最大分段长度
TCP_CALCULATE_EFF_SEND_MSS 1 tcp预计发送的分段长度,为1则根据窗口大小分配
TCP_SND_BUF (8*TCP_MSS) TCP发送缓冲区
TCP_SND_QUEUELEN (4*(TCP_SND_BUF/TCP_MSS)) TCP发送队列长度
TCP_SNDLOWAT (TCP_SND_BUF/4) TCP可发送数据长度
TCP_LISTEN_BACKLOG 1 TCP多连接允许
TCP_DEFAULT_LISTEN_BACKLOG 0xff TCP连接和半连接的总数
LWIP_TCP_TIMESTAMPS 0 TCP时间戳选项
TCP_WND_UPDATE_THRESHOLD (TCP_WND / 4) TCP窗口更新阈值
TCP_MSL 10000UL TCP连接存在时间 单位ms
TCP_FIN_WAIT_TIMEOUT 20000UL FIN等到ACK应答时间 单位ms
TCP_TMR_INTERVAL 20 TCP定时器计数间隔 20ms
PBUF_LINK_HLEN 14 为处理以太网头申请的包长度(本地MAC地址+远端MAC地址+协议类型)6+6+2
PBUF_POOL_BUFSIZE 256 单个内存池长度,要考虑到4字节对齐和最佳大小
ETH_PAD_SIZE 0 以太网填充长度,stm32设置为0 根据发送包判断
LWIP_TCPIP_CORE_LOCKING 0
LWIP_NETCONN 1 应用层使用NETCONN相关函数
LWIP_SOCKET 0 关闭SOCKET通讯
LWIP_COMPAT_SOCKETS 1
LWIP_POSIX_SOCKETS_IO_NAMES 1
LWIP_SO_RCVTIMEO 0 conn->acceptmbox/recvmbox接收有超时限制,超时后自动断开连接
LWIP_SO_RCVBUF 0
SO_REUSE 0
LWIP_STATS 0 LWIP统计选项
CHECKSUM_GEN_IP 1 IP校验和生成
CHECKSUM_GEN_UDP 1 UDP校验和生成
CHECKSUM_GEN_TCP 1 TCP校验和生成
CHECKSUM_CHECK_IP 1 IP校验和校验
CHECKSUM_CHECK_UDP 1 UDP校验和校验
CHECKSUM_CHECK_TCP 1 TCP校验和校验
LWIP_TCP_KEEPALIVE 1 tcp保活定时器
TCP_KEEPIDLE_DEFAULT 60000 保活时间 60s
TCP_KEEPINTVL_DEFAULT 10000 保活探测 10s
TCP_KEEPCNT_DEFAULT 9U
DEBUG_OPTIONS 0 调试代码
原作者:还没想好