日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

kmemleak的使用---内存泄露检测工具【转】

發(fā)布時間:2025/5/22 编程问答 18 豆豆
生活随笔 收集整理的這篇文章主要介紹了 kmemleak的使用---内存泄露检测工具【转】 小編覺得挺不錯的,現(xiàn)在分享給大家,幫大家做個參考.

目錄(?)[-]

  • 內核泄露檢測kmemleak
  • 介紹
  • 用法
  • 功能實現(xiàn)的基本方法原理
  • Kmemleak?API
  • 處理假陽性陰性
  • 限制和缺點
  • 測試的特定部分kmemleak
  • 內核泄露檢測(kmemleak)

    介紹:

    Kmemleak?提供了一種可選的內核泄漏檢測,其方法類似于跟蹤內存收集器。(http://en.wikipedia.org/wiki/Garbage_collection_%28computer_science%29#Tracing_garbage_collectors)當獨立的對象沒有被釋放時,其報告記錄在?/sys/kernel/debug/kmemleak中。

    用法:

    CONFIG_DEBUG_KMEMLEAK?在Kernel?hacking中被使能,一個內核線程每10分鐘(默認值)掃描內存,并打印發(fā)現(xiàn)新的未引用的對象的數(shù)量。

    查看內核打印信息詳細過程如下:

    1、掛載debugfs文件系統(tǒng)

    ???mount?-t?debugfs?nodev?/sys/kernel/debug/

    2、開啟內核自動檢測線程

    ???echo?scan?>?/sys/kernel/debug/kmemleak

    3、查看打印信息

    ???cat?/sys/kernel/debug/kmemleak

    4、清除內核檢測報告,新的內存泄露報告將重新寫入/sys/kernel/debug/kmemleak

    ???echo?clear?>?/sys/kernel/debug/kmemleak

    ?

    內存掃描參數(shù)可以進行修改通過向/sys/kernel/debug/kmemleak?文件寫入。?參數(shù)使用如下:

    ??off 禁用kmemleak(不可逆)

    ??stack=on 啟用任務堆棧掃描(default)

    ??stack=off 禁用任務堆棧掃描

    ??scan=on 啟動自動記憶掃描線程(default)

    ??scan=off 停止自動記憶掃描線程

    ??scan=<secs> 設置n秒內自動記憶掃描,默認600s

    ??scan 開啟內核掃描

    ??clear 清除內存泄露報告

    ??dump=<addr> 轉存信息對象在<addr>

    ?

    通過“kmemleak?=?OFF”,也可以在啟動時禁用Kmemleak在內核命令行。在初始化kmemleak之前,內存的分配或釋放這些動作被存儲在一個前期日志緩沖區(qū)。這個緩沖區(qū)的大小通過配CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE設置。

    ?

    功能實現(xiàn)的基本方法原理

    通過的kmalloc、vmalloc、kmem_cache_alloc等內存分配會跟蹤其指針,連同其他

    的分配大小和堆棧跟蹤信息,存儲在PRIO搜索樹。

    相應的釋放函數(shù)調用跟蹤和指針就會從kmemleak數(shù)據(jù)結構中移除。

    ?

    分配的內存塊,被認為是獨立的,如果沒有指針指向它起始地址或塊的內部的任何位置,可以發(fā)現(xiàn)掃描內存(包括已保存的寄存器)。這意味著,有可能沒有辦法為內核通過所分配的地址傳遞塊到一個釋放函數(shù),因此,該塊被認為是一個內存泄漏。

    ?

    掃描算法步驟:

    ?

    ??1。標記的所有分配對象為白色(稍后將剩余的白色物體

    ?????考慮獨立的)

    ??2。掃描存儲器與所述數(shù)據(jù)片段和棧開始,檢查對地址的值存儲在PRIO搜索樹。如果

    ?????一個白色的對象的指針被發(fā)現(xiàn),該對象將被添加到黑名單

    ??3。掃描的灰色對象匹配的地址(一些白色物體可以變成黑色,并添加結束時的黑名單),直到黑色集結束

    ??4。剩下的白色物體被認為是獨立兒,并報告寫入/sys/kernel/debug/kmemleak。

    ?

    一些分配的內存塊的指針在內核的內部數(shù)據(jù)結構和它們不能被檢測為孤兒。對

    避免這種情況,kmemleak也可以存儲的數(shù)量的值,指向一個

    內的塊的地址范圍內的地址,需要找到使

    塊不被認為是泄漏。其中一個例子是使用vmalloc()函數(shù)。

    Kmemleak?API

    ------------

    見include?/?linux?/?kmemleak.h中的函數(shù)原型的頭。

    kmemleak_init??-?初始化kmemleak

    kmemleak_alloc??-?一個內存塊分配的通知

    kmemleak_alloc_percpu??-?通知的一個percpu的內存塊分配

    kmemleak_free??-?通知的內存塊釋放

    kmemleak_free_part??-?通知釋放部分內存塊

    kmemleak_free_percpu??-?一個percpu內存塊釋放的通知

    kmemleak_not_leak??-?當不是泄露時,標記對象

    kmemleak_ignore??-?當泄漏時不掃描或報告對象

    kmemleak_scan_area??-?添加掃描區(qū)域內的內存塊

    kmemleak_no_scan??-?不掃描的內存塊

    kmemleak_erase??-?刪除一個指針變量的舊值

    kmemleak_alloc_recursive??-?為kmemleak_alloc,只檢查遞歸

    kmemleak_free_recursive??-?為kmemleak_free,只檢查遞歸

    ?

    處理假陽性/陰性

    --------------------------------------

    ?

    ?

    對于假性的內存泄漏,但不需要報告的,由于值的內存掃描過程中發(fā)現(xiàn)kmemleak是指向這樣的對象。為了減少假性報告的數(shù)目,kmemleak提供kmemleak_

    ignore,kmemleak_scan_area,kmemleak_no_scan,kmemleak_erase的功能,可以指定指針掃描方式,他們的掃描默認情況下不啟用。

    對于不能確定是否是內存泄露的,kmemleak提供kmemleak_not_leak。kmemleak_ignore的功能可以指定固定類型的數(shù)據(jù)是否需要掃描或打印,以上具體函數(shù)分析詳見3.3詳細處理處理過程及功能函數(shù)分析。

    有的泄露只是瞬間的,尤其是在SMP系統(tǒng),因為指針暫時存儲在CPU的寄存器或棧。當內存泄漏時Kmemleak定義MSECS_MIN_AGE(默認為1000)一個對象的最低時間。

    ?

    限制和缺點

    -------------------------

    ?

    主要缺點是減少了內存分配和性能釋放。為了避免其他開銷,只進行內存掃描,當在/?sys?/kernel/debug/?kmemleak文件被讀取。不管怎樣,這個工具是用于調試目的,其表現(xiàn)的性能不是重要的。為了保持算法簡單,kmemleak的值指向任何掃描一個塊的地址范圍內的地址。這可能會導致增加假陰性的報告。然而,它包括真正的內存泄漏,最終內存泄露將變得可見。

    假陰性的另一個來源是數(shù)據(jù)存儲在非指針值。

    在未來的版本中,kmemleak只能掃描指針成員中分配的結構。此功能解決了許多上述假陰性的情況下。

    該工具可能存在誤報。這些個案的分配塊可能不需要被釋放(如一些在init_call功能的情況下),這樣的指針通過其他方法計算,與通常的container_of宏或指針被存儲在一個位置相比不會被kmemleak掃描。頁分配和ioremap不被跟蹤

    測試的特定部分kmemleak

    ---------------------------------------

    在初始啟動時,/sys/kernel/debug/kmemleak輸出頁面比較多。這樣的情況下,當檢測指定已經開發(fā)的代碼錯誤時,可以通過清除/sys/kerner/debug/kmemleak的輸出。通過啟動kmemleak的掃描后,你可以找到新的未引用的對象,這應該與測試特定的代碼段。

    詳細步驟如下:

    要測試的關鍵部分之前需要清除kmemleak報告:

    echo?clear?>?/sys/kernel/debug/kmemleak

    測試你的內核或模塊...

    echo?scan?=5>?/sys/kernel/debug/kmemleak

    然后像往常一樣查看報告:

    cat?/sys/kernel/debug/kmemleak

    已經測試的實例詳見內核文檔kmenleak_test.txt文檔

    ?

    1:檢測內核內存泄漏的功能

    2:Documentation/kmemleak.txt 3:內核demo:mm/kmemleak-test.c 對于kmemleak,需要理解下面三點就可以了 1:我們需要知道它能檢測哪幾種內存泄漏(即用什么方法分配的內存可以檢測) 2:內核存在特殊情況,即分配內存但沒有引用。使用什么方法可以防止kmemleak report 3:檢測的機理是什么,如何知道分配的內存被引用,或者沒有引用。
    • 關注點1
    kmalloc/kzalloc vmalloc kmem_cache_alloc per_cpu [Page allocations and ioremap are not tracked]
    • 關注點2
    kmemleak_not_leak、kmemleak_ignore、kmemleak_no_scan 這幾個函數(shù)在內核中被使用,是為了不被kmemleak 打印出來。但是深層次的區(qū)別是什么? kmemleak_not_leak /**
    * kmemleak_not_leak - mark an allocated object as false positive
    * @ptr:??????? pointer to beginning of the object
    *
    * Calling this function on an object will cause the memory block to no longer
    * be reported as leak and always be scanned.
    */ 不打印;但是要掃描這個指針所分配的內存的內容。分配數(shù)據(jù)結構那么該結構本身不打印,但是會掃描結構內部的成員變量,是否引用其他指針。 這個函數(shù)往往用在:分配內存的內存永遠不會被釋放(與內核是一體,vmlinux或者不可移除的模塊一類)。 kmemleak_ignore /**
    * kmemleak_ignore - ignore an allocated object
    * @ptr:??????? pointer to beginning of the object
    *
    * Calling this function on an object will cause the memory block to be
    * ignored (not scanned and not reported as a leak). This is usually done when
    * it is known that the corresponding block is not a leak and does not contain
    * any references to other allocated memory blocks.
    */ 既不打印,也不掃描指針所指的數(shù)據(jù)結構的成員變量。如果知道分配的數(shù)據(jù)結構內部不包含其他引用(不含指針)。 kmemleak_no_scan /**
    * kmemleak_no_scan - do not scan an allocated object
    * @ptr:??????? pointer to beginning of the object
    *
    * This function notifies kmemleak not to scan the given memory block. Useful
    * in situations where it is known that the given object does not contain any
    * references to other objects. Kmemleak will not scan such objects reducing
    * the number of false negatives.
    */ 該指針本身被掃描,但是內容不會掃描。
    • 關注點3
    所謂reference即所分配的內存有指針引用。如果沒有任何指針引用那么肯定就是memleak。 所以要查找所有的指針的內容,來尋找其內容是否包含我們已經記錄的分配內存的地址(包括在其實地址+size之間)。 那么這些指針變量的 1:函數(shù)的局部變量 這些變量本身在棧中,所以需要檢測進程的內核棧 2:全局變量(整個系統(tǒng)/模塊內)靜態(tài)變量 這些變量是存在:ELF的bss/data? ? ? 這些變量可以通過查看vmlinux或者*.ko查看這類指針變量的區(qū)段。 可以通過objdump -x file? ? ---指針是靜態(tài)分配 3:指針本身是動態(tài)分配的,即動態(tài)分配內存塊(struct).成員變量是指針 所以必須要搜索這類動態(tài)分配的內存塊的內容。 通過objdump -x vmlinux .data where global tables, variables, etc. stand. objdump -s -j .data .process.o will hexdump it.? .bss don't look for bits of .bss in your file: there's none. That's where your?uninitialized?arrays and variable are, and the loader 'knows' they should be filled with zeroes ... there's no point storing more zeroes on your disk than there already are, is it??? ?.rodata
    ?? ? ?that's where your strings go, usually the things you forgot when linking and that cause your kernel not to work. objdump -s -j .rodata .process.o will hexdump it. Note that depending on the compiler, you may have more sections like this.
    .data..percpu
    • kmemleak_scan()
    data/bss 段掃描 /* data/bss scanning */ ???? scan_block(_sdata, _edata, NULL, 1);
    ???? scan_block(__bss_start, __bss_stop, NULL, 1); data..percpu #ifdef CONFIG_SMP
    ???? /* per-cpu sections scanning */
    ???? for_each_possible_cpu(i)
    ????????? scan_block(__per_cpu_start + per_cpu_offset(i),
    ?????????????? ?? __per_cpu_end + per_cpu_offset(i), NULL, 1);
    #endif -->>>>以上都是全局指針變量、per_cpu變量 struct pagep[]數(shù)組 /*??
    ???????? * Struct page scanning for each node.
    ???????? */
    ??????? lock_memory_hotplug();
    ??????? for_each_online_node(i) {
    ??????????????? pg_data_t *pgdat = NODE_DATA(i);
    ??????????????? unsigned long start_pfn = pgdat->node_start_pfn;
    ??????????????? unsigned long end_pfn = start_pfn + pgdat->node_spanned_pages;
    ??????????????? unsigned long pfn;

    ??????????????? for (pfn = start_pfn; pfn < end_pfn; pfn++) {
    ??????????????????????? struct page *page;

    ??????????????????????? if (!pfn_valid(pfn))
    ??????????????????????????????? continue;
    ??????????????????????? page = pfn_to_page(pfn);
    ??????????????????????? /* only scan if page is in use */
    ??????????????????????? if (page_count(page) == 0)
    ??????????????????????????????? continue;
    ??????????????????????? scan_block(page, page + 1, NULL, 1);
    ??????????????? }???
    ??????? }???
    ??????? unlock_memory_hotplug(); 內核struct page數(shù)組是動態(tài)分配的,所以也要單獨的進行檢測。 內核進程棧 if (kmemleak_stack_scan) {
    ????????? struct task_struct *p, *g;

    ????????? read_lock(&tasklist_lock);
    ????????? do_each_thread(g, p) {
    ?????????????? scan_block(task_stack_page(p), task_stack_page(p) +
    ??????????????????? ?? THREAD_SIZE, NULL, 0);
    ????????? } while_each_thread(g, p);
    ????????? read_unlock(&tasklist_lock);
    ? ? ? 一般遍歷內核所有的進程用的是:for_each_process(); 但是這里卻使用:do_each_thread(){};while_each_thread() >>>for_each_process:只打印進程;而不打印進程內的線程 >>>do_each_thread(){};while_each_thread():打印進程以及進程內的線程信息。這是因為線程有自己單獨的內核棧信息。 分配的內存塊的內部 分配一塊內存(一般是分配數(shù)據(jù)結構),內部的成員變量是指針,所以這部分也需要檢測。 >>>???? scan_gray_list();---->scan_object(): 掃描分配內存的全部內容或者部分內容,是否引用其他指針。 pointer+size
    • 問題
    1:讀代碼理解下面的掃描 struct A*a ---> struct A { struct B * b------>struct B { struct C *c ------->struct C 如果struct A *a = NULL

    總結

    以上是生活随笔為你收集整理的kmemleak的使用---内存泄露检测工具【转】的全部內容,希望文章能夠幫你解決所遇到的問題。

    如果覺得生活随笔網(wǎng)站內容還不錯,歡迎將生活随笔推薦給好友。