Linux內(nèi)核內(nèi)存泄漏怎么搞?
1、Kmemleak介紹
在Linux內(nèi)核開(kāi)發(fā)中,Kmemleak是一種用于檢測(cè)內(nèi)核中內(nèi)存泄漏的工具。
(資料圖片)
內(nèi)存泄漏指的是程序中已經(jīng)不再使用的內(nèi)存沒(méi)有被妥善地釋放,導(dǎo)致內(nèi)存的浪費(fèi)。內(nèi)核中的內(nèi)存泄漏同樣會(huì)導(dǎo)致系統(tǒng)性能下降、系統(tǒng)崩潰等問(wèn)題。
Kmemleak能夠檢測(cè)內(nèi)核中的內(nèi)存泄漏,通過(guò)檢測(cè)內(nèi)核中未被釋放但又無(wú)法找到其使用位置的內(nèi)存,進(jìn)一步定位、修復(fù)內(nèi)存泄漏的問(wèn)題。
在用戶空間,我們常用Valgrind來(lái)檢測(cè);
在內(nèi)核空間,我們常用Kmemleak來(lái)檢測(cè)。
2、如何使用Kmemleak
2.1 內(nèi)核配置
內(nèi)核打開(kāi)相應(yīng)配置:
CONFIG_DEBUG_KMEMLEAK:Kmemleak被加入到內(nèi)核
CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE設(shè)置為16000:該參數(shù)為記錄內(nèi)存泄露信息的內(nèi)存池,越大記錄信息越多。
CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF :Kmemleak默認(rèn)開(kāi)關(guān)狀態(tài)
依賴的配置:
CONFIG_DEBUG_KERNEL:打開(kāi)內(nèi)核調(diào)試功能
CONFIG_DEBUG_FS:需要借助到debugfs
CONFIG_STACKTRACE:記錄進(jìn)程的堆棧信息
2.2 用戶空間配置
我們要想使用Kmemleak,需要掛在debugfs,來(lái)查看泄露的情況。
進(jìn)入文件系統(tǒng)后,進(jìn)行掛載:
mount-tdebugfsnodev/sys/kernel/debug/#掛在debugfs
設(shè)置掃描時(shí)間:
echoscan=10>/sys/kernel/debug/kmemleak#10S掃描一次
默認(rèn)內(nèi)存泄露檢測(cè)時(shí)間為10min,上面設(shè)置為10s一次
查看泄露情況:
cat/sys/kernel/debug/kmemleak#查看內(nèi)存泄露情況
其他指令:
echoscan>/sys/kernel/debug/kmemleak#觸發(fā)一次掃描echoclear>/sys/kernel/debug/kmemleak#清除當(dāng)前kmemleak記錄的泄露信息echooff>/sys/kernel/debug/kmemleak#關(guān)閉kmemleak(不可逆轉(zhuǎn)的)echostack=off>/sys/kernel/debug/kmemleak#關(guān)閉任務(wù)棧掃描echostack=on>/sys/kernel/debug/kmemleak#使能任務(wù)棧掃描echoscan=on>/sys/kernel/debug/kmemleak#啟動(dòng)自動(dòng)內(nèi)存掃描線程echoscan=off>/sys/kernel/debug/kmemleak#停止自動(dòng)內(nèi)存掃描線程echoscan=>/sys/kernel/debug/kmemleak#設(shè)置自動(dòng)掃描線程掃描間隔,默認(rèn)是600,設(shè)置0則是停止掃描echodump=>/sys/kernel/debug/kmemleak#dump某個(gè)地址的內(nèi)存塊信息,比如上面的echodump=0xffffffc008efd200>/sys/kernel/debug/kmemleak即可查看詳細(xì)信息
2.3 通過(guò)Linux啟動(dòng)參數(shù)控制開(kāi)關(guān)
Kmemleak的默認(rèn)開(kāi)關(guān)狀態(tài)可以通過(guò)CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF 配置來(lái)控制,當(dāng)然也可以通過(guò)向Linux內(nèi)核啟動(dòng)參數(shù)中加入kmemleak=off來(lái)控制。
3、Kmemleak原理
Kmemleak提供了一種跟蹤垃圾回收器tracing garbage collector的原理,來(lái)檢測(cè)內(nèi)核中存在的內(nèi)存泄露,其不同之處在于:孤立的對(duì)象并沒(méi)有被釋放掉,而是通過(guò)/sys/kernel/debug/kmemleak僅僅被報(bào)告。
這種方法同樣應(yīng)用于Valgrind中,不過(guò)該工具主要用于檢測(cè)用戶空間不同應(yīng)用的內(nèi)存泄露情況。
在用戶空間,我們常用Valgrind來(lái)檢測(cè)應(yīng)用進(jìn)程;
在內(nèi)核空間,我們常用Kmemleak來(lái)檢測(cè)內(nèi)核代碼。
通過(guò)kmalloc()、vmalloc()、kmem_cache_alloc()等函數(shù)分配內(nèi)存時(shí),會(huì)跟蹤指針,堆棧等信息,將其存儲(chǔ)在一個(gè)紅黑樹(shù)中。
同時(shí)跟蹤相應(yīng)的釋放函數(shù)調(diào)用,并從kmemleak數(shù)據(jù)結(jié)構(gòu)中刪除指針。
簡(jiǎn)單理解:相當(dāng)于追蹤內(nèi)存分配相關(guān)接口,記錄分配內(nèi)存的首地址,堆棧大小等信息,在內(nèi)存釋放階段將其刪除。
我們通過(guò)查看相關(guān)內(nèi)核文檔可知,內(nèi)存泄露檢測(cè)的掃描算法步驟如下:
將所有對(duì)象標(biāo)記為白色(最后剩余的白色對(duì)象將被視為孤立對(duì)象)
從數(shù)據(jù)段和堆棧開(kāi)始掃描內(nèi)存,根據(jù)紅黑樹(shù)中存儲(chǔ)的地址信息來(lái)檢查值,如果找到指向白色對(duì)象的指針,則添加到灰色列表
掃描灰色列表以查找地址匹配的對(duì)象,直到灰色列表完成
剩下的白色對(duì)象被視為孤立對(duì)象,并通過(guò)/sys/kernel/debug/kmemleak進(jìn)行報(bào)告
4、Kmemleak API接口
kmemleak_init-初始化kmemleakkmemleak_alloc-內(nèi)存塊分配通知kmemleak_alloc_percpu-通知percpu內(nèi)存塊分配kmemleak_vmalloc-通知vmalloc()內(nèi)存分配kmemleak_free-通知內(nèi)存塊釋放kmemleak_free_part-通知釋放部分內(nèi)存塊kmemleak_free_percpu-通知percpu內(nèi)存塊釋放kmemleak_update_trace-更新對(duì)象分配堆棧跟蹤kmemleak_not_leak-將對(duì)象標(biāo)記為非泄漏kmemleak_ignore-不掃描或報(bào)告對(duì)象泄漏kmemleak_scan_area-在內(nèi)存塊內(nèi)添加掃描區(qū)域kmemleak_no_scan-不掃描內(nèi)存塊kmemleak_erase-擦除指針變量中的舊值kmemleak_alloc_recursive-作為kmemleak_alloc,但檢查遞歸性kmemleak_free_recursive-作為kmemleak_free,但檢查遞歸性
5、Kmemleak特殊情況
漏報(bào):真正內(nèi)存泄露了,但是未報(bào)告,因?yàn)樵趦?nèi)存掃描期間找到的值指向此類對(duì)象。為了減少誤報(bào)的數(shù)量,kmemleak提供了kmemleak_ignore,kmemleak_scan_area,kmemleak_no_scan和kmemleak_erase功能
誤報(bào):實(shí)際沒(méi)有泄露,但是卻錯(cuò)誤的報(bào)告了內(nèi)存泄露。kmemleak提供了kmemleak_not_leak功能。
6、Kmemleak驗(yàn)證
內(nèi)核也提供了一個(gè)示例:kmemleak-test模塊,該模塊用以判斷是否打開(kāi)了Kmemleak功能。通過(guò)配置CONFIG_DEBUG_KMEMLEAK_TEST選項(xiàng)可以選擇。
#modprobekmemleak-test#echoscan>/sys/kernel/debug/kmemleak
#cat/sys/kernel/debug/kmemleakunreferencedobject0xffff89862ca702e8(size32):comm"modprobe",pid2088,jiffies4294680594(age375.486s)hexdump(first32bytes):6b6b6b6b6b6b6b6b6b6b6b6b6b6b6b6bkkkkkkkkkkkkkkkk6b6b6b6b6b6b6b6b6b6b6b6b6b6b6ba5kkkkkkkkkkkkkkk.backtrace:[<00000000e0a73ec7>]0xffffffffc01d2036[<000000000c5d2a46>]do_one_initcall+0x41/0x1df[<0000000046db7e0a>]do_init_module+0x55/0x200[<00000000542b9814>]load_module+0x203c/0x2480[<00000000c2850256>]__do_sys_finit_module+0xba/0xe0[<000000006564e7ef>]do_syscall_64+0x43/0x110[<000000007c873fa6>]entry_SYSCALL_64_after_hwframe+0x44/0xa9...審核編輯:湯梓紅
標(biāo)簽: