前段时间写的一个转发模块在现网应用后
几台设备出现了不同程度的内存泄露
大约4-15天设备内存耗尽
泄露速度因业务压力和网络丢包情况而不同
经历了N次的代码review和一个不眠之夜后
终于找到了原因
在一处释放skb的地方
本应该使用kfree_skb()的,鬼使神差的被我敲成了kfree()
教训很深刻
遂仔细查看了相关函数
以SLUB分配方式为例
alloc_skb()位于include/linux/skbuff.h中
是对__alloc_skb()的内联封装函数,快速克隆标志为0
在__alloc_skb()中根据fclone标志从缓存skbuff_fclone_cache或skbuff_head_cache中分配struct sk_buff控制结构
随后根据size分配按缓存线对齐的线性区长度空间
skbuff_fclone_cache和skbuff_head_cache由skb_init()调用kmem_cache_create()初始化
kfree_skb()位于net/core/skbuff.c中
进行必要的判断后根据情况调用__kfree_skb()
在__kfree_skb()中会调用skb_release_all()和kfree_skbmem()函数
skb_release_all()中执行路由、连接跟踪、析构函数、网桥控制等清理工作
并释放skb下的页数据、分片skb、线性区buffer
在kfree_skbmem()中使用kmem_cache_free()回收控制结构skb本身
而在kmem_cache_free()调用slab_free()函数
kfree()位于mm/slub.c中
参数为void *类型
gcc中void *和其他类型指针字段隐式转换,没有编译警告
然后调用了slab_free()
如此一看,内存泄露无疑
因为kfree()并不会释放skb的线性区及分片等
各函数的详细分析在 git://github.com/kernel-digger/linux.git 的comments分支
欢迎clone查看交流
Linux内核:kfree()误用引发的内存泄露问题
某转发模块在现网应用后出现内存泄露问题,经过排查发现是将原本应使用的kfree_skb()错误地替换成了kfree()。这导致struct sk_buff的线性区和分片未被正确释放,从而引发内存泄露。文章详细分析了alloc_skb()、kfree_skb()和kfree()等函数的工作原理,并提供了问题修复的思路。
260

被折叠的 条评论
为什么被折叠?



