linux内核内存泄露检测

linux内核内存泄露检测,第1张

经常碰到系统跑着跑着一段时间内存满了,出现内存泄漏的问题,系统软件太庞大,这类问题又不好直接从源码中分析,所以需要借助工具来分析了,kmemleak就是这样的一个工具。

在Kernel hacking中打开CONFIG_DEBUG_KMEMLEAK =y即使能了kmemleak,其实就是开了一个内核线程,该内核线程每10分钟(默认值)扫描内存,并打印发现新的未引用的对象的数量。kmemleak的原理其实就是通过kmalloc、vmalloc、kmem_cache_alloc等内存的分配,跟踪其指针,连同其他的分配大小和堆栈跟踪信息,存储在PRIO搜索树。如果存在相应的释放函数调用跟踪和指针,就会从kmemleak数据结构中移除。下面我们看看具体的用法。

查看内核打印信息详细过程如下:

1、挂载debugfs文件系统

   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

内存扫描参数可以进行修改通过向/sys/kernel/debug/kmemleak 文件写入。 参数使用如下:

  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之前,内存的分配或释放这些动作被存储在一个前期日志缓冲区。这个缓冲区的大小通过配CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE设置。

虽然之前一直听说过 ftrace,但从来没将它用在实战中,在一次客户排查问题中,遇到了比较奇怪的现象,一位精通内核的朋友建议使用 ftrace 来定位一下。虽然那一次并没有使用 ftrace,但也让我觉得,后面我们势必要提供 ftrace 相关的工具帮助我们在线上定位问题,所以自己也决定重新学习使用下 ftrace,当然也决定写一系列的相关出来,这里就先简单介绍下 ftrace。

首先我们需要知道,什么是 ftrace?根据 Linux Doc 的介绍,ftrace 是一个 Linux 内部的 trace 工具,能够帮助开发者和系统设计者知道内核当前正在干啥,从而更好的去分析性能问题。

Ftrace 能帮我们分析内核特定的事件,譬如调度,中断等,也能帮我们去追踪动态的内核函数,以及这些函数的调用栈还有栈的使用这些。它也能帮我们去追踪延迟,譬如中断被屏蔽,抢占被禁止的时间,以及唤醒一个进程之后多久开始执行的时间。

可以看到,使用 ftrace 真的能做到对系统内核非常系统的剖析,甚至都能通过 ftrace 来学习 Linux 内核,不过在更进一步之前,我们需要学会的是 - 如何使用 ftrace。

要使用 ftrace,首先就是需要将系统的 debugfs 或者 tracefs 给挂载到某个地方,幸运的是,几乎所有的 Linux 发行版,都开启了 debugfs/tracefs 的支持,所以我们也没必要去重新编译内核了。

在比较老的内核版本,譬如 CentOS 7 的上面,debugfs 通常被挂载到 /sys/kernel/debug 上面(debug 目录下面有一个 tracing 目录),而比较新的内核,则是将 tracefs 挂载到 /sys/kernel/tracing ,无论是什么,我都喜欢将 tracing 目录直接 link 到 /tracing 。后面都会假设直接进入了 /tracing 目录,后面,我会使用 Ubuntu 16.04 来举例子,内核版本是 4.13 来举例子。

我们使用 ls 来看看目录下面到底有什么:

可以看到,里面有非常多的文件和目录,具体的含义,大家可以去详细的看官方文档的解释,后面只会重点介绍一些文件。

我们可以通过 available_tracers 这个文件知道当前 ftrace 支持哪些插件。

通常用的最多的就是 function 和 function_graph ,当然,如果我们不想 trace 了,可以使用 nop 。我们首先打开 function :

上面我们将 function 写入到了 current_tracer 来开启 function 的 trace,我通常会在 cat 下 current_tracer 这个文件,主要是防止自己写错了。

然后 ftrace 就开始工作了,会将相关的 trace 信息放到 trace 文件里面,我们直接读取这个文件就能获取相关的信息。

我们可以设置只跟踪特定的 function

当然,如果我们不想 trace schedule 这个函数,也可以这样做:

或者也可以这样做:

Function filter 的设置也支持 *match , match* , *match* 这样的正则表达式,譬如我们可以 echo '*lock*' <set_ftrace_notrace 来禁止跟踪带 lock 的函数, set_ftrace_notrace 文件里面这时候就会显示:

相比于 function , function_graph 能让我们更加详细的去知道内核函数的上下文,我们打开 function_graph :

我们也可以只跟踪某一个函数的堆栈

上面提到了 function 的 trace,在 ftrace 里面,另外用的多的就是 event 的 trace,我们可以在 events 目录下面看支持那些事件:

上面列出来的都是分组的,我们可以继续深入下去,譬如下面是查看 sched 相关的事件:

对于某一个具体的事件,我们也可以查看:

不知道大家注意到了没有,上述目录里面,都有一个 enable 的文件,我们只需要往里面写入 1,就可以开始 trace 这个事件。譬如下面就开始 trace sched_wakeup 这个事件:

我们也可以 trace sched 里面的所有事件:

当然也可以 trace 所有的事件:

从上面的例子可以看到,其实使用 ftrace 并不是那么方便,我们需要手动的去控制多个文件,但幸运的是,我们有 trace-cmd ,作为 ftrace 的前端, trace-cmd 能够非常方便的让我们进行 ftrace 的 *** 作,譬如我们可以使用 record 命令来 trace sched 事件:

然后使用 report 命令来查看 trace 的数据:

当然,在 report 的时候也可以加入自己的 filter 来过滤数据,譬如下面,我们就过滤出 sched_wakeup 事件并且是 success 为 1 的。

大家可以注意下 success == 1 ,这其实是一个对事件里面 field 进行的表达式运算了,对于不同的事件,我们可以通过查看起 format 来知道它的实际 fields 是怎样的,譬如:

上面只是简单的列出了 ftrace 相关的使用,后续我会在写一些我们或者业界是如何用 ftrace 来解决问题的。另外,我们正在用 ftrace 开发非常多的性能诊断工具,如果你对这一块感兴趣,欢迎联系我 tl@pingcap.com 。


欢迎分享,转载请注明来源:内存溢出

原文地址:https://54852.com/yw/7550581.html

(0)
打赏 微信扫一扫微信扫一扫 支付宝扫一扫支付宝扫一扫
上一篇 2023-04-07
下一篇2023-04-07

发表评论

登录后才能评论

评论列表(0条)

    保存