誤用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查看交流


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章