在 Linux 核心中,sk_buff(簡稱 skb)是網路封包處理的核心資料結構。理解其釋放流程,對於排查記憶體洩漏、分析網路效能瓶頸至關重要。本文梳理進程退出與發送完成兩大場景下的 skb 釋放路徑。
當用戶進程呼叫 exit() 結束時,核心會依序執行以下釋放動作:
用戶態 exit()
→ 核心 do_exit()
→ exit_files()
→ put_files_struct()
→ close_files()
→ filp_close()
→ __fput()
→ file->f_op->release(inode, file)
→ sock_close()
→ sock_release()
→ inet_release()
→ sk->sk_prot->close(sk, timeout)
→ tcp_close()
→ __kfree_skb()
→ kfree_skbmem
├─ skb_release_data // 釋放 data 所佔用的 page
└─ kmem_cache_free // 從 slab 快取釋放 skb 結構體本身
→ release_sock()
→ sock_put()
封包經驅動程式發送完成後,會在 TX 完成中斷(或 NAPI poll)上下文中,由驅動呼叫 dev_kfree_skb_irq() 或 napi_consume_skb() 直接釋放 skb,路徑較短,避免進程上下文切換開銷。
skb->users 參考計數與 SKB_TRUESIZE 追蹤記憶體歸屬,防止重複釋放。skb->destructor 存在,會先執行解構器(如 `sock_wfree`),再歸還頁框與 slab 物件。/proc/net/softnet_stat、cat /proc/slabinfo | grep skbuff 監控 skb 分配/釋放頻率。掌握上述流程,有助於在高併發網路服務開發中精準定位 skb 相關的記憶體問題。