?sphinx.addnodesdocument)}( rawsourcechildren]( translations LanguagesNode)}(hhh](h pending_xref)}(hhh]docutils.nodesTextEnglish}parenthsba attributes}(ids]classes]names]dupnames]backrefs] refdomainstdreftypedoc reftarget/dev-tools/kmemleakmodnameN classnameN refexplicitutagnamehhh ubh)}(hhh]hChinese (Traditional)}hh2sbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/zh_TW/dev-tools/kmemleakmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hItalian}hhFsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/it_IT/dev-tools/kmemleakmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hJapanese}hhZsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/ja_JP/dev-tools/kmemleakmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hKorean}hhnsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/ko_KR/dev-tools/kmemleakmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hPortuguese (Brazilian)}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/pt_BR/dev-tools/kmemleakmodnameN classnameN refexplicituh1hhh ubh)}(hhh]hSpanish}hhsbah}(h]h ]h"]h$]h&] refdomainh)reftypeh+ reftarget&/translations/sp_SP/dev-tools/kmemleakmodnameN classnameN refexplicituh1hhh ubeh}(h]h ]h"]h$]h&]current_languageChinese (Simplified)uh1h hh _documenthsourceNlineNubhcomment)}(h SPDX-License-Identifier: GPL-2.0h]h SPDX-License-Identifier: GPL-2.0}hhsbah}(h]h ]h"]h$]h&] xml:spacepreserveuh1hhhhhhS/var/lib/git/docbuild/linux/Documentation/translations/zh_CN/dev-tools/kmemleak.rsthKubhnote)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]h paragraph)}(hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。h]hX{此文件的目的是为让中文读者更容易阅读和理解,而不是作为一个分支。 因此, 如果您对此文件有任何意见或更新,请先尝试更新原始英文文件。 如果您发现本文档与原始文件有任何不同或者有翻译问题,请发建议或者补丁给 该文件的译者,或者请求中文文档维护者和审阅者的帮助。}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hh5Documentation/translations/zh_CN/disclaimer-zh_CN.rsthKhhubah}(h]h ]h"]h$]h&]uh1hhhhhhhhNubh field_list)}(hhh](hfield)}(hhh](h field_name)}(hOriginalh]hOriginal}(hhhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhhhKubh field_body)}(h$Documentation/dev-tools/kmemleak.rsth]h)}(hjh]h$Documentation/dev-tools/kmemleak.rst}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1hhhubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubh)}(hhh](h)}(h Translatorh]h Translator}(hj!hhhNhNubah}(h]h ]h"]h$]h&]uh1hhjhhhKubj)}(h2刘浩阳 Haoyang Liu h]h)}(h1刘浩阳 Haoyang Liu h](h刘浩阳 Haoyang Liu <}(hj3hhhNhNubh reference)}(htttturtleruss@hust.edu.cnh]htttturtleruss@hust.edu.cn}(hj=hhhNhNubah}(h]h ]h"]h$]h&]refuri mailto:tttturtleruss@hust.edu.cnuh1j;hj3ubh>}(hj3hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj/ubah}(h]h ]h"]h$]h&]uh1hhjubeh}(h]h ]h"]h$]h&]uh1hhhhKhhhhubeh}(h]h ]h"]h$]h&]uh1hhhhhhhhKubhsection)}(hhh](htitle)}(h内核内存泄露检测器h]h内核内存泄露检测器}(hjphhhNhNubah}(h]h ]h"]h$]h&]uh1jnhjkhhhhhK ubh)}(hXKmemleak 提供了一个类似 `可追踪的垃圾收集器 `_ 的方法来检测可能的内核内存泄漏,不同的是孤立对象不会 被释放,而是仅通过 /sys/kernel/debug/kmemleak 报告。Valgrind 工具 (``memcheck --leak-check``)使用了一种相似的方法来检测用户空间应用中的内存泄 露。h](hKmemleak 提供了一个类似 }(hj~hhhNhNubj<)}(hZ`可追踪的垃圾收集器 `_h]h可追踪的垃圾收集器}(hjhhhNhNubah}(h]h ]h"]h$]h&]name可追踪的垃圾收集器refuri8https://en.wikipedia.org/wiki/Tracing_garbage_collectionuh1j;hj~ubhtarget)}(h< h]h}(h]id2ah ]h"]可追踪的垃圾收集器ah$]h&]refurijuh1j referencedKhj~ubh 的方法来检测可能的内核内存泄漏,不同的是孤立对象不会 被释放,而是仅通过 /sys/kernel/debug/kmemleak 报告。Valgrind 工具 (}(hj~hhhNhNubhliteral)}(h``memcheck --leak-check``h]hmemcheck --leak-check}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj~ubhR)使用了一种相似的方法来检测用户空间应用中的内存泄 露。}(hj~hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK hjkhhubjj)}(hhh](jo)}(h用法h]h用法}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jnhjhhhhhKubh)}(h"Kernel hacking" 中的 CONFIG_DEBUG_KMEMLEAK 必须被启用。一个内核线程每10分钟 (默认情况下)扫描一次内存,并且打印出新发现的未被引用的对象个数。 如果 ``debugfs`` 没有挂载,则执行::h](h“Kernel hacking” 中的 CONFIG_DEBUG_KMEMLEAK 必须被启用。一个内核线程每10分钟 (默认情况下)扫描一次内存,并且打印出新发现的未被引用的对象个数。 如果 }(hjhhhNhNubj)}(h ``debugfs``h]hdebugfs}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh 没有挂载,则执行:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjhhubh literal_block)}(h+# mount -t debugfs nodev /sys/kernel/debug/h]h+# mount -t debugfs nodev /sys/kernel/debug/}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h>显示所有扫描出的可能的内存泄漏的细节信息::h]h=显示所有扫描出的可能的内存泄漏的细节信息:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(h # cat /sys/kernel/debug/kmemleakh]h # cat /sys/kernel/debug/kmemleak}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubh)}(h)启动一次中等程度的内存扫描::h]h(启动一次中等程度的内存扫描:}(hj#hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(h(# echo scan > /sys/kernel/debug/kmemleakh]h(# echo scan > /sys/kernel/debug/kmemleak}hj1sbah}(h]h ]h"]h$]h&]hhuh1jhhhK hjhhubh)}(h/清空当前所有可能的内存泄露列表::h]h.清空当前所有可能的内存泄露列表:}(hj?hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK"hjhhubj)}(h)# echo clear > /sys/kernel/debug/kmemleakh]h)# echo clear > /sys/kernel/debug/kmemleak}hjMsbah}(h]h ]h"]h$]h&]hhuh1jhhhK$hjhhubh)}(h~当再次读取 ``/sys/kernel/debug/kmemleak`` 文件时,将会输出自上次扫描以来检测到的 新的内存泄露。h](h当再次读取 }(hj[hhhNhNubj)}(h``/sys/kernel/debug/kmemleak``h]h/sys/kernel/debug/kmemleak}(hjchhhNhNubah}(h]h ]h"]h$]h&]uh1jhj[ubhP 文件时,将会输出自上次扫描以来检测到的 新的内存泄露。}(hj[hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK&hjhhubh)}(h注意,孤立目标是通过被分配时间来排序的,列表开始的对象可能会导致后续的对象都被 识别为孤立对象。h]h注意,孤立目标是通过被分配时间来排序的,列表开始的对象可能会导致后续的对象都被 识别为孤立对象。}(hj{hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK)hjhhubh)}(h{可以通过写入 ``/sys/kernel/debug/kmemleak`` 文件在运行时修改内存扫描参数。下面是 支持的参数:h](h可以通过写入 }(hjhhhNhNubj)}(h``/sys/kernel/debug/kmemleak``h]h/sys/kernel/debug/kmemleak}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubhJ 文件在运行时修改内存扫描参数。下面是 支持的参数:}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhK,hjhhubh bullet_list)}(hhh](h list_item)}(h$off 禁用 kmemleak(不可逆)h]hdefinition_list)}(hhh]hdefinition_list_item)}(h"off 禁用 kmemleak(不可逆)h](hterm)}(hoffh]hoff}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK0hjubh definition)}(hhh]h)}(h禁用 kmemleak(不可逆)h]h禁用 kmemleak(不可逆)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK1hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK0hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(h,stack=on 开启任务栈扫描(默认)h]j)}(hhh]j)}(h*stack=on 开启任务栈扫描(默认)h](j)}(hstack=onh]hstack=on}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK2hjubj)}(hhh]h)}(h!开启任务栈扫描(默认)h]h!开启任务栈扫描(默认)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK3hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK2hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(h!stack=off 禁用任务栈扫描h]j)}(hhh]j)}(hstack=off 禁用任务栈扫描h](j)}(h stack=offh]h stack=off}(hjGhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK4hjCubj)}(hhh]h)}(h禁用任务栈扫描h]h禁用任务栈扫描}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK5hjUubah}(h]h ]h"]h$]h&]uh1jhjCubeh}(h]h ]h"]h$]h&]uh1jhhhK4hj@ubah}(h]h ]h"]h$]h&]uh1jhj<ubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(h4scan=on 开启自动内存扫描线程(默认)h]j)}(hhh]j)}(h2scan=on 开启自动内存扫描线程(默认)h](j)}(hscan=onh]hscan=on}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK6hjubj)}(hhh]h)}(h*开启自动内存扫描线程(默认)h]h*开启自动内存扫描线程(默认)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK7hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK6hjubah}(h]h ]h"]h$]h&]uh1jhj~ubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(h)scan=off 关闭自动内存扫描线程h]j)}(hhh]j)}(h'scan=off 关闭自动内存扫描线程h](j)}(hscan=offh]hscan=off}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK8hjubj)}(hhh]h)}(h关闭自动内存扫描线程h]h关闭自动内存扫描线程}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK9hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK8hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(hscan=; 设定自动内存扫描间隔,以秒为单位(默认值为 600,设置为 0 表示停 止自动扫描)h]j)}(hhh]j)}(h{scan=; 设定自动内存扫描间隔,以秒为单位(默认值为 600,设置为 0 表示停 止自动扫描)h](j)}(h scan=;h]h scan=;}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK;hj ubj)}(hhh]h)}(hn设定自动内存扫描间隔,以秒为单位(默认值为 600,设置为 0 表示停 止自动扫描)h]hn设定自动内存扫描间隔,以秒为单位(默认值为 600,设置为 0 表示停 止自动扫描)}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK;hjubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhhhK;hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(hscan 触发一次内存扫描h]j)}(hhh]j)}(hscan 触发一次内存扫描h](j)}(hscanh]hscan}(hjOhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK=hjKubj)}(hhh]h)}(h触发一次内存扫描h]h触发一次内存扫描}(hj`hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK>hj]ubah}(h]h ]h"]h$]h&]uh1jhjKubeh}(h]h ]h"]h$]h&]uh1jhhhK=hjHubah}(h]h ]h"]h$]h&]uh1jhjDubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(hclear 通过标记所有当前已报告的未被引用对象为灰,从而清空当前可能的内存泄露列 表;如果 kmemleak 被禁用,则释放所有 kmemleak 对象,。h]j)}(hhh]j)}(hclear 通过标记所有当前已报告的未被引用对象为灰,从而清空当前可能的内存泄露列 表;如果 kmemleak 被禁用,则释放所有 kmemleak 对象,。h](j)}(hclearh]hclear}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhK@hjubj)}(hhh]h)}(h通过标记所有当前已报告的未被引用对象为灰,从而清空当前可能的内存泄露列 表;如果 kmemleak 被禁用,则释放所有 kmemleak 对象,。h]h通过标记所有当前已报告的未被引用对象为灰,从而清空当前可能的内存泄露列 表;如果 kmemleak 被禁用,则释放所有 kmemleak 对象,。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK@hjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhK@hjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubj)}(h8dump= 输出存储在 中的对象信息 h]j)}(hhh]j)}(h6dump= 输出存储在 中的对象信息 h](j)}(h dump=h]h dump=}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhhhKChjubj)}(hhh]h)}(h)输出存储在 中的对象信息h]h)输出存储在 中的对象信息}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKChjubah}(h]h ]h"]h$]h&]uh1jhjubeh}(h]h ]h"]h$]h&]uh1jhhhKChjubah}(h]h ]h"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]uh1jhjhhhNhNubeh}(h]h ]h"]h$]h&]bullet*uh1jhhhK0hjhhubh)}(hc可以通过在内核命令行中传递 ``kmemleak=off`` 参数从而在启动时禁用 Kmemleak。h](h(可以通过在内核命令行中传递 }(hjhhhNhNubj)}(h``kmemleak=off``h]h kmemleak=off}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh+ 参数从而在启动时禁用 Kmemleak。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKEhjhhubh)}(h在 kmemleak 初始化之前就可能会有内存分配或释放,这些操作被存储在一个早期日志缓 冲区中。缓冲区的大小通过 CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE 选项配置。h]h在 kmemleak 初始化之前就可能会有内存分配或释放,这些操作被存储在一个早期日志缓 冲区中。缓冲区的大小通过 CONFIG_DEBUG_KMEMLEAK_MEM_POOL_SIZE 选项配置。}(hj2hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKGhjhhubh)}(h如果 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF 被启用,则 kmemleak 默认被禁用。在内核命 令行中传递 ``kmemleak=on`` 参数来开启这个功能。h](hq如果 CONFIG_DEBUG_KMEMLEAK_DEFAULT_OFF 被启用,则 kmemleak 默认被禁用。在内核命 令行中传递 }(hj@hhhNhNubj)}(h``kmemleak=on``h]h kmemleak=on}(hjHhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj@ubh 参数来开启这个功能。}(hj@hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKJhjhhubh)}(h如果出现 "Error while writing to stdout" 或 "write_loop: Invalid argument" 这样 的错误,请确认 kmemleak 被正确启用。h]h如果出现 “Error while writing to stdout” 或 “write_loop: Invalid argument” 这样 的错误,请确认 kmemleak 被正确启用。}(hj`hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKMhjhhubeh}(h]id3ah ]h"]用法ah$]h&]uh1jihjkhhhhhKubjj)}(hhh](jo)}(h 基础算法h]h 基础算法}(hjyhhhNhNubah}(h]h ]h"]h$]h&]uh1jnhjvhhhhhKQubh)}(hX&通过 :c:func:`kmalloc`, :c:func:`vmalloc`, :c:func:`kmem_cache_alloc` 以及同类 函数均被跟踪,指针,包括一些额外的信息如大小和栈追踪等,都被存储在红黑树中。 对应的释放函数调用也被追踪,并从 kmemleak 数据结构中移除相应指针。h](h通过 }(hjhhhNhNubh)}(h:c:func:`kmalloc`h]j)}(hjh]h kmalloc()}(hjhhhNhNubah}(h]h ](xrefcc-funceh"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]refdoc%translations/zh_CN/dev-tools/kmemleak refdomainjreftypefunc refexplicitrefwarn reftargetkmallocuh1hhhhKShjubh, }(hjhhhNhNubh)}(h:c:func:`vmalloc`h]j)}(hjh]h vmalloc()}(hjhhhNhNubah}(h]h ](jjc-funceh"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]refdocj refdomainjreftypefunc refexplicitrefwarnjvmallocuh1hhhhKShjubh, }hjsbh)}(h:c:func:`kmem_cache_alloc`h]j)}(hjh]hkmem_cache_alloc()}(hjhhhNhNubah}(h]h ](jjc-funceh"]h$]h&]uh1jhjubah}(h]h ]h"]h$]h&]refdocj refdomainjreftypefunc refexplicitrefwarnjkmem_cache_allocuh1hhhhKShjubh 以及同类 函数均被跟踪,指针,包括一些额外的信息如大小和栈追踪等,都被存储在红黑树中。 对应的释放函数调用也被追踪,并从 kmemleak 数据结构中移除相应指针。}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKShjvhhubh)}(hXC对于一个已分配的内存块,如果通过扫描内存(包括保存寄存器)没有发现任何指针指向 它的起始地址或者其中的任何位置,则认为这块内存是孤立的。这意味着内核无法将该内 存块的地址传递给一个释放内存函数,这块内存便被认为泄露了。h]hXC对于一个已分配的内存块,如果通过扫描内存(包括保存寄存器)没有发现任何指针指向 它的起始地址或者其中的任何位置,则认为这块内存是孤立的。这意味着内核无法将该内 存块的地址传递给一个释放内存函数,这块内存便被认为泄露了。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKWhjvhhubh)}(h扫描算法步骤:h]h扫描算法步骤:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK[hjvhhubh block_quote)}(hX1. 标记所有对象为白色(最后剩下的白色对象被认为是孤立的) 2. 从数据节和栈开始扫描内存,检测每个值是否是红黑树中存储的地址。如果一个指向 白色对象的指针被检测到,则将该对象标记为灰色。 3. 扫描灰色对象引用的其他对象(有些白色对象可能会变为灰色并被添加到灰名单末尾 )直到灰名单为空。 4. 剩余的白色对象就被认为是孤立的并通过 /sys/kernel/debug/kmemleak 报告。 h]henumerated_list)}(hhh](j)}(hQ标记所有对象为白色(最后剩下的白色对象被认为是孤立的)h]h)}(hj+h]hQ标记所有对象为白色(最后剩下的白色对象被认为是孤立的)}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK]hj)ubah}(h]h ]h"]h$]h&]uh1jhj&ubj)}(h从数据节和栈开始扫描内存,检测每个值是否是红黑树中存储的地址。如果一个指向 白色对象的指针被检测到,则将该对象标记为灰色。h]h)}(h从数据节和栈开始扫描内存,检测每个值是否是红黑树中存储的地址。如果一个指向 白色对象的指针被检测到,则将该对象标记为灰色。h]h从数据节和栈开始扫描内存,检测每个值是否是红黑树中存储的地址。如果一个指向 白色对象的指针被检测到,则将该对象标记为灰色。}(hjDhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK^hj@ubah}(h]h ]h"]h$]h&]uh1jhj&ubj)}(h扫描灰色对象引用的其他对象(有些白色对象可能会变为灰色并被添加到灰名单末尾 )直到灰名单为空。h]h)}(h扫描灰色对象引用的其他对象(有些白色对象可能会变为灰色并被添加到灰名单末尾 )直到灰名单为空。h]h扫描灰色对象引用的其他对象(有些白色对象可能会变为灰色并被添加到灰名单末尾 )直到灰名单为空。}(hj\hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK`hjXubah}(h]h ]h"]h$]h&]uh1jhj&ubj)}(h\剩余的白色对象就被认为是孤立的并通过 /sys/kernel/debug/kmemleak 报告。 h]h)}(h[剩余的白色对象就被认为是孤立的并通过 /sys/kernel/debug/kmemleak 报告。h]h[剩余的白色对象就被认为是孤立的并通过 /sys/kernel/debug/kmemleak 报告。}(hjthhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKbhjpubah}(h]h ]h"]h$]h&]uh1jhj&ubeh}(h]h ]h"]h$]h&]enumtypearabicprefixhsuffix.uh1j$hj ubah}(h]h ]h"]h$]h&]uh1jhhhK]hjvhhubh)}(hXC有些指向已分配的内存块的指针存储在内核内部的数据结构中,它们不能被检测为孤立。 为了避免这种情况,kmemleak 也存储了指向需要被查找的内存块范围内的任意地址的地址 数量,如此一来这些内存便不会被认为泄露。一个例子是 __vmalloc()。h]hXC有些指向已分配的内存块的指针存储在内核内部的数据结构中,它们不能被检测为孤立。 为了避免这种情况,kmemleak 也存储了指向需要被查找的内存块范围内的任意地址的地址 数量,如此一来这些内存便不会被认为泄露。一个例子是 __vmalloc()。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKdhjvhhubeh}(h]id4ah ]h"] 基础算法ah$]h&]uh1jihjkhhhhhKQubjj)}(hhh](jo)}(h用 kmemleak 测试特定部分h]h用 kmemleak 测试特定部分}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jnhjhhhhhKiubh)}(hX在初始化启动阶段 /sys/kernel/debug/kmemleak 的输出可能会很多,这也可能是你在开发 时编写的漏洞百出的代码导致的。为了解决这种情况你可以使用 'clear' 命令来清除 /sys/kernel/debug/kmemleak 输出的所有的未引用对象。在执行 'clear' 后执行 'scan' 可以发现新的未引用对象,这将会有利你测试代码的特定部分。h]hX在初始化启动阶段 /sys/kernel/debug/kmemleak 的输出可能会很多,这也可能是你在开发 时编写的漏洞百出的代码导致的。为了解决这种情况你可以使用 ‘clear’ 命令来清除 /sys/kernel/debug/kmemleak 输出的所有的未引用对象。在执行 ‘clear’ 后执行 ‘scan’ 可以发现新的未引用对象,这将会有利你测试代码的特定部分。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKkhjhhubh)}(hB为了用一个空的 kmemleak 测试一个特定部分,执行::h]hA为了用一个空的 kmemleak 测试一个特定部分,执行:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKphjhhubj)}(hy# echo clear > /sys/kernel/debug/kmemleak ... 测试你的内核或者模块 ... # echo scan > /sys/kernel/debug/kmemleakh]hy# echo clear > /sys/kernel/debug/kmemleak ... 测试你的内核或者模块 ... # echo scan > /sys/kernel/debug/kmemleak}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKrhjhhubh)}(h#然后像平常一样获得报告::h]h"然后像平常一样获得报告:}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKvhjhhubj)}(h # cat /sys/kernel/debug/kmemleakh]h # cat /sys/kernel/debug/kmemleak}hjsbah}(h]h ]h"]h$]h&]hhuh1jhhhKxhjhhubeh}(h]kmemleakah ]h"]用 kmemleak 测试特定部分ah$]h&]uh1jihjkhhhhhKiubjj)}(hhh](jo)}(h释放 kmemleak 内核对象h]h释放 kmemleak 内核对象}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jnhjhhhhhK{ubh)}(h为了允许访问先前发现的内存泄露,当用户禁用或发生致命错误导致 kmemleak 被禁用时,内核中的 kmemleak 对象不会被释放。这些对象可能会占用很大 一部分物理内存。h]h为了允许访问先前发现的内存泄露,当用户禁用或发生致命错误导致 kmemleak 被禁用时,内核中的 kmemleak 对象不会被释放。这些对象可能会占用很大 一部分物理内存。}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhK}hjhhubh)}(hA在这种情况下,你可以用如下命令回收这些内存::h]h@在这种情况下,你可以用如下命令回收这些内存:}(hj-hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjhhubj)}(h)# echo clear > /sys/kernel/debug/kmemleakh]h)# echo clear > /sys/kernel/debug/kmemleak}hj;sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhjhhubeh}(h]id5ah ]h"]释放 kmemleak 内核对象ah$]h&]uh1jihjkhhhhhK{ubjj)}(hhh](jo)}(h Kmemleak APIh]h Kmemleak API}(hjThhhNhNubah}(h]h ]h"]h$]h&]uh1jnhjQhhhhhKubh)}(h>在 include/linux/kmemleak.h 头文件中查看函数原型:h]h>在 include/linux/kmemleak.h 头文件中查看函数原型:}(hjbhhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjQhhubj)}(hhh](j)}(h&``kmemleak_init`` - 初始化 kmemleakh]h)}(hjuh](j)}(h``kmemleak_init``h]h kmemleak_init}(hjzhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjwubh - 初始化 kmemleak}(hjwhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjsubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h3``kmemleak_alloc`` - 通知一个内存块的分配h]h)}(hjh](j)}(h``kmemleak_alloc``h]hkmemleak_alloc}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh! - 通知一个内存块的分配}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(hE``kmemleak_alloc_percpu`` - 通知一个 percpu 类型的内存分配h]h)}(hjh](j)}(h``kmemleak_alloc_percpu``h]hkmemleak_alloc_percpu}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh, - 通知一个 percpu 类型的内存分配}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(hC``kmemleak_vmalloc`` - 通知一个使用 vmalloc() 的内存分配h]h)}(hjh](j)}(h``kmemleak_vmalloc``h]hkmemleak_vmalloc}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh/ - 通知一个使用 vmalloc() 的内存分配}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h2``kmemleak_free`` - 通知一个内存块的释放h]h)}(hj h](j)}(h``kmemleak_free``h]h kmemleak_free}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh! - 通知一个内存块的释放}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h:``kmemleak_free_part`` - 通知一个部分的内存释放h]h)}(hj.h](j)}(h``kmemleak_free_part``h]hkmemleak_free_part}(hj3hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj0ubh$ - 通知一个部分的内存释放}(hj0hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj,ubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(hD``kmemleak_free_percpu`` - 通知一个 percpu 类型的内存释放h]h)}(hjSh](j)}(h``kmemleak_free_percpu``h]hkmemleak_free_percpu}(hjXhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjUubh, - 通知一个 percpu 类型的内存释放}(hjUhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjQubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h@``kmemleak_update_trace`` - 更新分配对象过程的栈追踪h]h)}(hjxh](j)}(h``kmemleak_update_trace``h]hkmemleak_update_trace}(hj}hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjzubh' - 更新分配对象过程的栈追踪}(hjzhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjvubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h?``kmemleak_not_leak`` - 标记一个对象内存为未泄露的h]h)}(hjh](j)}(h``kmemleak_not_leak``h]hkmemleak_not_leak}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh* - 标记一个对象内存为未泄露的}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(hC``kmemleak_ignore`` - 不要扫描或报告某个对象未泄露的h]h)}(hjh](j)}(h``kmemleak_ignore``h]hkmemleak_ignore}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh0 - 不要扫描或报告某个对象未泄露的}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h:``kmemleak_scan_area`` - 在内存块中添加扫描区域h]h)}(hjh](j)}(h``kmemleak_scan_area``h]hkmemleak_scan_area}(hjhhhNhNubah}(h]h ]h"]h$]h&]uh1jhjubh$ - 在内存块中添加扫描区域}(hjhhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhjubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h/``kmemleak_no_scan`` - 不扫描某个内存块h]h)}(hj h](j)}(h``kmemleak_no_scan``h]hkmemleak_no_scan}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh - 不扫描某个内存块}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(h<``kmemleak_erase`` - 在指针变量中移除某个旧的值h]h)}(hj1 h](j)}(h``kmemleak_erase``h]hkmemleak_erase}(hj6 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj3 ubh* - 在指针变量中移除某个旧的值}(hj3 hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj/ ubah}(h]h ]h"]h$]h&]uh1jhjphhhhhNubj)}(hj``kmemleak_alloc_recursive`` - 和 kmemleak_alloc 效果相同但会检查是否有递归的 内存分配h]j)}(hhh]j)}(hi``kmemleak_alloc_recursive`` - 和 kmemleak_alloc 效果相同但会检查是否有递归的 内存分配h](j)}(h\``kmemleak_alloc_recursive`` - 和 kmemleak_alloc 效果相同但会检查是否有递归的h](j)}(h``kmemleak_alloc_recursive``h]hkmemleak_alloc_recursive}(hjc hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj_ ubh@ - 和 kmemleak_alloc 效果相同但会检查是否有递归的}(hj_ hhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhKhj[ ubj)}(hhh]h)}(h 内存分配h]h 内存分配}(hj~ hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj{ ubah}(h]h ]h"]h$]h&]uh1jhj[ ubeh}(h]h ]h"]h$]h&]uh1jhhhKhjX ubah}(h]h ]h"]h$]h&]uh1jhjT ubah}(h]h ]h"]h$]h&]uh1jhjphhhNhNubj)}(hi``kmemleak_free_recursive`` - 和 kmemleak_free 效果相同但会检查是否有递归的 内存释放 h]j)}(hhh]j)}(hh``kmemleak_free_recursive`` - 和 kmemleak_free 效果相同但会检查是否有递归的 内存释放 h](j)}(hZ``kmemleak_free_recursive`` - 和 kmemleak_free 效果相同但会检查是否有递归的h](j)}(h``kmemleak_free_recursive``h]hkmemleak_free_recursive}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubh? - 和 kmemleak_free 效果相同但会检查是否有递归的}(hj hhhNhNubeh}(h]h ]h"]h$]h&]uh1jhhhKhj ubj)}(hhh]h)}(h 内存释放h]h 内存释放}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubeh}(h]h ]h"]h$]h&]uh1jhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1jhjphhhNhNubeh}(h]h ]h"]h$]h&]j-uh1jhhhKhjQhhubh)}(h{下列函数使用一个物理地址作为对象指针并且只在地址有一个 lowmem 映射时做出相应的 行为:h]h{下列函数使用一个物理地址作为对象指针并且只在地址有一个 lowmem 映射时做出相应的 行为:}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhjQhhubj)}(hhh](j)}(h``kmemleak_alloc_phys``h]h)}(hj h]j)}(hj h]hkmemleak_alloc_phys}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj ubah}(h]h ]h"]h$]h&]uh1hhhhKhj ubah}(h]h ]h"]h$]h&]uh1jhj hhhhhNubj)}(h``kmemleak_free_part_phys``h]h)}(hj. h]j)}(hj. h]hkmemleak_free_part_phys}(hj3 hhhNhNubah}(h]h ]h"]h$]h&]uh1jhj0 ubah}(h]h ]h"]h$]h&]uh1hhhhKhj, ubah}(h]h ]h"]h$]h&]uh1jhj hhhhhNubj)}(h``kmemleak_ignore_phys`` h]h)}(h``kmemleak_ignore_phys``h]j)}(hjR h]hkmemleak_ignore_phys}(hjT hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjP ubah}(h]h ]h"]h$]h&]uh1hhhhKhjL ubah}(h]h ]h"]h$]h&]uh1jhj hhhhhNubeh}(h]h ]h"]h$]h&]jj uh1jhhhKhjQhhubeh}(h] kmemleak-apiah ]h"] kmemleak apiah$]h&]uh1jihjkhhhhhKubjj)}(hhh](jo)}(h解决假阳性/假阴性h]h解决假阳性/假阴性}(hj~ hhhNhNubah}(h]h ]h"]h$]h&]uh1jnhj{ hhhhhKubh)}(hXy假阴性是指由于在内存扫描中有值指向该对象导致 kmemleak 没有报告的实际存在的内存 泄露(孤立对象)。为了减少假阴性的出现次数,kmemleak 提供了 kmemleak_ignore, kmemleak_scan_area,kmemleak_no_scan 和 kmemleak_erase 函数(见上)。 任务栈也会增加假阴性的数量并且默认不开启对它们的扫描。h]hXy假阴性是指由于在内存扫描中有值指向该对象导致 kmemleak 没有报告的实际存在的内存 泄露(孤立对象)。为了减少假阴性的出现次数,kmemleak 提供了 kmemleak_ignore, kmemleak_scan_area,kmemleak_no_scan 和 kmemleak_erase 函数(见上)。 任务栈也会增加假阴性的数量并且默认不开启对它们的扫描。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj{ hhubh)}(hX假阳性是对象被误报为内存泄露(孤立对象)。对于已知未泄露的对象,kmemleak 提供了 kmemleak_not_leak 函数。同时 kmemleak_ignore 可以用于标记已知不包含任何 其他指针的内存块,标记后该内存块不会再被扫描。h]hX假阳性是对象被误报为内存泄露(孤立对象)。对于已知未泄露的对象,kmemleak 提供了 kmemleak_not_leak 函数。同时 kmemleak_ignore 可以用于标记已知不包含任何 其他指针的内存块,标记后该内存块不会再被扫描。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj{ hhubh)}(hX一些被报告的泄露仅仅是暂时的,尤其是在 SMP(对称多处理)系统中,因为其指针 暂存在 CPU 寄存器或栈中。Kmemleak 定义了 MSECS_MIN_AGE(默认值为 1000) 来表示一个被报告为内存泄露的对象的最小存活时间。h]hX一些被报告的泄露仅仅是暂时的,尤其是在 SMP(对称多处理)系统中,因为其指针 暂存在 CPU 寄存器或栈中。Kmemleak 定义了 MSECS_MIN_AGE(默认值为 1000) 来表示一个被报告为内存泄露的对象的最小存活时间。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj{ hhubeh}(h]id6ah ]h"]解决假阳性/假阴性ah$]h&]uh1jihjkhhhhhKubjj)}(hhh](jo)}(h限制和缺点h]h限制和缺点}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jnhj hhhhhKubh)}(hX主要的缺点是内存分配和释放的性能下降。为了避免其他的损失,只有当 /sys/kernel/debug/kmemleak 文件被读取时才会进行内存扫描。无论如何,这个工具是出于 调试的目标,性能表现可能不是最重要的。h]hX主要的缺点是内存分配和释放的性能下降。为了避免其他的损失,只有当 /sys/kernel/debug/kmemleak 文件被读取时才会进行内存扫描。无论如何,这个工具是出于 调试的目标,性能表现可能不是最重要的。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubh)}(h为了保持算法简单,kmemleak 寻找指向某个内存块范围中的任何值。这可能会引发假阴性 现象的出现。但是,最后一个真正的内存泄露也会变得明显。h]h为了保持算法简单,kmemleak 寻找指向某个内存块范围中的任何值。这可能会引发假阴性 现象的出现。但是,最后一个真正的内存泄露也会变得明显。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubh)}(h非指针值的数据是假阴性的另一个来源。在将来的版本中,kmemleak 仅仅会扫 描已分配结构体中的指针成员。这个特性会解决上述很多的假阴性情况。h]h非指针值的数据是假阴性的另一个来源。在将来的版本中,kmemleak 仅仅会扫 描已分配结构体中的指针成员。这个特性会解决上述很多的假阴性情况。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubh)}(hXKmemleak 会报告假阳性。这可能发生在某些被分配的内存块不需要被释放的情况下 (某些 init_call 函数中),指针的计算是通过其他方法而不是常规的 container_of 宏 或是指针被存储在 kmemleak 没有扫描的地方。h]hXKmemleak 会报告假阳性。这可能发生在某些被分配的内存块不需要被释放的情况下 (某些 init_call 函数中),指针的计算是通过其他方法而不是常规的 container_of 宏 或是指针被存储在 kmemleak 没有扫描的地方。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubh)}(h'页分配和 ioremap 不会被追踪。h]h'页分配和 ioremap 不会被追踪。}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubeh}(h]id7ah ]h"]限制和缺点ah$]h&]uh1jihjkhhhhhKubjj)}(hhh](jo)}(h使用 kmemleak-test 测试h]h使用 kmemleak-test 测试}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jnhj hhhhhKubh)}(hX为了检测是否成功启用了 kmemleak,你可以使用一个故意制造内存泄露的模块 kmemleak-test。设置 CONFIG_SAMPLE_KMEMLEAK 为模块(不能作为内建模块使用) 并且启动启用了 kmemleak 的内核。加载模块并执行一次扫描::h]hX 为了检测是否成功启用了 kmemleak,你可以使用一个故意制造内存泄露的模块 kmemleak-test。设置 CONFIG_SAMPLE_KMEMLEAK 为模块(不能作为内建模块使用) 并且启动启用了 kmemleak 的内核。加载模块并执行一次扫描:}(hj. hhhNhNubah}(h]h ]h"]h$]h&]uh1hhhhKhj hhubj)}(hA# modprobe kmemleak-test # echo scan > /sys/kernel/debug/kmemleakh]hA# modprobe kmemleak-test # echo scan > /sys/kernel/debug/kmemleak}hj< sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhj hhubh)}(h注意你可能无法立刻或在第一次扫描后得到结果。当 kmemleak 得到结果,将会输出日 志 ``kmemleak: new suspected memory leaks`` 。然后通过读取文件 获取信息::h](hr注意你可能无法立刻或在第一次扫描后得到结果。当 kmemleak 得到结果,将会输出日 志 }(hjJ hhhNhNubj)}(h9``kmemleak: new suspected memory leaks``h]h5kmemleak: new suspected memory leaks}(hjR hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjJ ubh* 。然后通过读取文件 获取信息:}(hjJ hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj hhubj)}(hX# cat /sys/kernel/debug/kmemleak unreferenced object 0xffff89862ca702e8 (size 32): comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s) hex dump (first 32 bytes): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. 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 ...h]hX# cat /sys/kernel/debug/kmemleak unreferenced object 0xffff89862ca702e8 (size 32): comm "modprobe", pid 2088, jiffies 4294680594 (age 375.486s) hex dump (first 32 bytes): 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b kkkkkkkkkkkkkkkk 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b 6b a5 kkkkkkkkkkkkkkk. 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 ...}hjj sbah}(h]h ]h"]h$]h&]hhuh1jhhhKhj hhubh)}(hS用 ``rmmod kmemleak_test`` 移除模块时也会触发 kmemleak 的结果输出。h](h用 }(hjx hhhNhNubj)}(h``rmmod kmemleak_test``h]hrmmod kmemleak_test}(hj hhhNhNubah}(h]h ]h"]h$]h&]uh1jhjx ubh8 移除模块时也会触发 kmemleak 的结果输出。}(hjx hhhNhNubeh}(h]h ]h"]h$]h&]uh1hhhhKhj hhubeh}(h] kmemleak-testah ]h"]使用 kmemleak-test 测试ah$]h&]uh1jihjkhhhhhKubeh}(h]id1ah ]h"]内核内存泄露检测器ah$]h&]uh1jihhhhhhhK ubeh}(h]h ]h"]h$]h&]sourcehuh1hcurrent_sourceN current_lineNsettingsdocutils.frontendValues)}(jnN generatorN datestampN source_linkN source_urlN toc_backlinksentryfootnote_backlinksK sectnum_xformKstrip_commentsNstrip_elements_with_classesN strip_classesN report_levelK halt_levelKexit_status_levelKdebugNwarning_streamN tracebackinput_encoding utf-8-siginput_encoding_error_handlerstrictoutput_encodingutf-8output_encoding_error_handlerj error_encodingutf-8error_encoding_error_handlerbackslashreplace language_codeenrecord_dependenciesNconfigN id_prefixhauto_id_prefixid dump_settingsNdump_internalsNdump_transformsNdump_pseudo_xmlNexpose_internalsNstrict_visitorN_disable_configN_sourcehnj _destinationN _config_files]7/var/lib/git/docbuild/linux/Documentation/docutils.confafile_insertion_enabled raw_enabledKline_length_limitM'pep_referencesN pep_base_urlhttps://peps.python.org/pep_file_url_templatepep-%04drfc_referencesN rfc_base_url&https://datatracker.ietf.org/doc/html/ tab_widthKtrim_footnote_reference_spacesyntax_highlightlong smart_quotessmartquotes_locales]character_level_inline_markupdoctitle_xform docinfo_xformKsectsubtitle_xform image_loadinglinkembed_stylesheetcloak_email_addressessection_self_linkenvNubreporterNindirect_targets]substitution_defs}substitution_names}refnames}refids}nameids}(j j jjjsjpjjj jjNjKjx ju j j j j j j u nametypes}(j jjsjj jNjx j j j uh}(j jkjjjpjjjvjjjKjju jQj j{ j j j j u footnote_refs} citation_refs} autofootnotes]autofootnote_refs]symbol_footnotes]symbol_footnote_refs] footnotes] citations]autofootnote_startKsymbol_footnote_startK id_counter collectionsCounter}j KsRparse_messages]transform_messages] transformerN include_log]7Documentation/translations/zh_CN/dev-tools/kmemleak.rst(NNNNta decorationNhhub.