一次解决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阅码场”,扫描下方二维码关注