LWIP memory leak: solved
LWIP内存泄露问题
最近在项目中遇到了使用LWIP 1.4.1协议栈内存泄露的问题。表现为使用socket进行通信过程中,有时fd 资源已释放的情况下,网络堆内存依然没被释放。经过长时间的积累,导致无法申请网络堆内存。
这种情况在网络物理连接断开的情况下特别容易出现,比如插拔网线。
问题分析
- TCP三握手四挥手 。是否因为close fd 时TimeWait时间较长,导致网络堆内存释放慢。
在代码中没有搜索到与TimeWait相关的参数,因此只能想其他办法。 - LWIP 释放内存出Bug 。
通过内存检测工具定位内存泄露的位置。排查原因。
解决问题过程
-
通过对问题分析中提到的第二点进行了调试,在网上找到一个好用的内存泄露检测工具memleak (非常适合嵌入式C平台), 进行内存调试。
memleak 下载地址
sourceforge下载源码地址:http://sourceforge.net/projects/memleak/通过定位,发现是在tcp 发送相关的lwip函数调用中没有释放内存。还发现通过get_socket函数找到fd并调用tcp_abort函数主动释放堆内存能解决问题。
但这个方法非常不安全,因为破坏了LWIP内部机制。
-
在无意中注意到lwipopts.h中配置文件关于KeepAlive的心跳检测机制的参数。这个正确设置好了就能解决LWIP内存泄露的问题。
#define TCP_KEEPIDLE_DEFAULT 10000UL
#define TCP_KEEPINTVL_DEFAULT 1000UL
#define TCP_KEEPCNT_DEFAULT 10U
搜索代码发现这个参数默认值是上述宏配置,可以通过setsockopt函数配置针对心跳包时间进行修改。
之前工程中有设置这个选项,但不起作用。现在深入看了LWIP源码,才发现里面涉及到单位转换问题。
如果单位搞错了,就不起作用了。
在sockets.h文件中,看到了与时间单位相关的参数。
/*
* Options for level IPPROTO_TCP
*/
#define TCP_NODELAY 0x01 /* don't delay send to coalesce packets */
#define TCP_KEEPALIVE 0x02