【问题记录】kmemleak 定位内存泄露

一、内存泄露问题

在项目开发过程,有时候通过 free 命令发现可用内存在逐渐减少,但是通过 top 或者 pidstat -r 等工具看不到异常占用内存进程的情况,可能存在以下原因:

  1. 内存泄漏。一些内存使用方式会导致系统逐渐耗尽内存,这种情况下内存可能是在内核 space 中占用。
  2. 系统缓存。系统会将一些文件和数据缓存到可用内存中,如果一段时间内没有被使用,缓存的内容就会逐渐增加。这种情况下,通过 free 命令可以看到使用缓存时 available 数值降低的情况。即使没有进程明显占用内存,系统也可能运行缓慢。

二、判断内存是否泄露

  1. 通过 free、cat /proc/meminfo 查看可用内存是否逐渐减少 【结果分析】平均每小时内存减少 21MB。
  2. 通过 cat /proc/slabinfo 确认内存减少的对象 【结果分析】减少最多的是 kmalloc-1024,内存存在泄露。

三、使用KMEM来定位内存泄露代码

1. kmemleak

kmemleak 是 Linux 内核用于检测内存泄露的一种工具,实现的基本原理是通过对 kmalloc()、vmalloc()、kmem_cache_alloc() 等内存分配接口,跟踪其分配的指针、分配内存大小、堆栈等跟踪信息,存储在 kmemleak 数据结构中。

2. 内核配置

c 复制代码
+CONFIG_DEBUG_KMEMLEAK=y
+CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE=20000  // 这个值应设置较大,不然会有下面的问题
+# CONFIG_DEBUG_KMEMLEAK_TEST is not set

在启动阶段,由于默认 CONFIG_DEBUG_KMEMLEAK_EARLY_LOG_SIZE 配置过小,系统启动阶段 early log 溢出,会导致 kmemleak 被自动禁用,log 如下:

c 复制代码
[    0.000000] kmemleak: Kernel memory leak detector disabled
[    0.000000] clk r_dsp_cache0 not found in of_sunxi_periph_cpus_clk_setup
[    0.000000] clk r_dsp_cache1 not found in of_sunxi_periph_cpus_clk_setup
[    0.000000] clocksource: timer: mask: 0xffffffff max_cycles: 0xffffffff, max_idle_ns: 79635851949 ns
[    0.000000] arm_arch_timer: Architected cp15 timer(s) running at 24.00MHz (virt).
[    0.000000] clocksource: arch_sys_counter: mask: 0xffffffffffffff max_cycles: 0x588fe9dc0, max_idle_ns: 440795202592 ns
[    0.000005] sched_clock: 56 bits at 24MHz, resolution 41ns, wraps every 4398046511097ns
[    0.008203] Console: colour dummy device 80x25
[    0.012434] kmemleak: Early log buffer exceeded (1438), please increase DEBUG_KMEMLEAK_EARLY_LOG_SIZE

3. 使用方式

c 复制代码
1、挂载debugfs
    mount -t debugfs nodev /sys/kernel/debug/
2、内核线程每10分钟(默认情况下)扫描一次,并打印找到的可疑的内存泄漏object。也可以在任意时刻执行kmemleak的内存扫描。
    echo scan > /sys/kernel/debug/kmemleak
3、详细的输出信息通过/sys/kernel/debug/kmemleak获取。
    cat /sys/kernel/debug/kmemleak

四、应用现场

【结果分析】可以看到是在e1mcc_pppd 进程在系统调用时,对tty 操作中调用了 alloc_tty_struct 函数里面去申请的内存,但是这段内存并没有释放掉,所以造成了内存泄露。


五、总结

在某些复杂的项目中,如果存在内存泄露问题,而又无法通过常规的命令工具去定位问题,若通过代码去逐步排查也很难去排查出来,通过kmemleak工具就可以很好的帮我们定位出来内存泄露的具体代码处,进而缩小问题的范围。比如上面的示例中,定位出来是 tty_open 函数内申请的内存,那对应的应该想到是不是在tty_close或者对应的退出函数中该段内存没有去释放掉,可以通过添加打印来逐步排查。

相关推荐
写代码的学渣5 小时前
ubuntu 22.04 新装的系统 xshell 连不上
linux·运维·ubuntu
序属秋秋秋5 小时前
《Linux系统编程之进程环境》【环境变量】
linux·运维·服务器·c语言·c++·操作系统·系统编程
云计算练习生6 小时前
linux shell编程实战 10 Git工具详解与运维场景实战
linux·运维·git
虚伪的空想家8 小时前
KVM的ubuntu虚机如何关闭安全启动
linux·安全·ubuntu
t1987512814 小时前
在Ubuntu 22.04系统上安装libimobiledevice
linux·运维·ubuntu
skywalk816314 小时前
linux安装Code Server 以便Comate IDE和CodeBuddy等都可以远程连上来
linux·运维·服务器·vscode·comate
晚风吹人醒.15 小时前
缓存中间件Redis安装及功能演示、企业案例
linux·数据库·redis·ubuntu·缓存·中间件
Hard but lovely15 小时前
linux: pthread库的使用和理解
linux
这儿有一堆花17 小时前
Kali Linux:探测存活到挖掘漏洞
linux·运维·服务器
松涛和鸣17 小时前
从零开始理解 C 语言函数指针与回调机制
linux·c语言·开发语言·嵌入式硬件·排序算法