误用kfree()释放skb导致内存泄露

前段时间写的一个转发模块在现网应用后

几台设备出现了不同程度的内存泄露

大约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内核)