一次解决Linux内核内存泄漏实战全过程

什么是内存泄漏:

程序向系统申请内存,使用完不需要之后
, 不释放内存还给系统回收,造成申请的内存被浪费
.
发现系统中内存使用量随着时间的流逝,消耗的越来越多,例如下图所示:

接下来的排查思路是
:

1. 监控系统中每个用户进程消耗的
PSS ( 使用
pmap 工具
(pmap pid)).

PSS: 按比例报告的物理内存,比如进程
A 占用
20M 物理内存,进程
B 和进程
A 共享
5M 物理内存,那么进程
A
PSS 就是
(20 – 5) + 5/2 = 17.5M

2. 监控
/proc/meminfo 输出
, 重点观察
Slab 使用量

slab 对应的
/proc/slabinfo 信息

3. 参考
/proc/meminfo 输出,计算系统中未被统计的内存变化,比如内核驱动代码

直接调用
alloc_page()
buddy 中拿走的内存不会被单独统计

以上排查思路分别对应下图中的
1,2,3 :


在排查的过程中发现系统非常空闲,都没有跑任何用户业务进程。

其中在使用
slabtop 监控
slab 的使用情况时发现
size-4096 不停增长

通过监控
/proc/slabinfo
也发现
SReclaimable
的使用量不停增长

while true; 
do
sleep 1 ;
cat /proc/slabinfo >> /tmp/slabinfo.txt ;
echo "===" >> /tmp/slabinfo.txt ;
done

由此判断很可能是内核空间在使用
size-4096 时发生了内存泄漏
.

接下来使用
trace event(tracepoint) 功能来监控
size-4096 的使用和释放过程,

主要用来跟踪
kmalloc()
kfree() 函数对应的
trace event, 因为他们的
trace event 被触发之后会打印
kmalloc()
kfree() 所申请和释放的内存地址
, 然后进一步只过滤申请
4096 字节的情况。

#trace-cmd record -e kmalloc
-f 'bytes_alloc==4096' -e kfree -T

(-T 打印堆栈
)

等待几分钟之后

#ctrl  ^c 中断
trace-cmd
#trace-cmd report
以上步骤相当于:

等待几分钟之后

#cp /sys/kernel/debug/tracing/trace_pipe  /tmp/kmalloc-trace


trace-cmd report 的输出结果来看,很多
kmalloc 对应的
ptr 值都
没有
kfree 与之对应

ptr

这就说明了
cat 进程在内核空间使用
size-4096 之后并没有释放,造成了内存泄漏。

为了进一步精确定位到是使用哪个内核函数造成的问题,此时手动触发
vmcore

#echo c > /proc/sysrq-trigger

然后使用
crash 工具分析
vmcore

#crash ./vmcore ./vmlinux.debug

读出上面
kmalloc 申请的
ptr 内存信息

( 读取
0xffff880423744000
内存开始的
4096
个字节,并以字符形式显示
)

发现从上面几个
ptr 内存中读出的内容都是非常相似,仔细看一下发现都是
/proc/schedstat 的输出内容。

通过阅读相关代码发现,当读出
/proc/schedstat 内容之后,确实没有释放内存

然后发现
kernel 上游已经有
patch 解决了这个问题:

commit: 8e0bcc722289
fix a leak in /proc/schedstats
更多精彩,尽在”Linux阅码场”,扫描下方二维码关注

别忘了分享、点赞或者在看哦~