Linux内核内存泄露排查实战:从/proc/meminfo到slabinfo的保姆级指南

张开发
2026/6/5 16:43:25 15 分钟阅读

分享文章

Linux内核内存泄露排查实战:从/proc/meminfo到slabinfo的保姆级指南
Linux内核内存泄露排查实战从/proc/meminfo到slabinfo的保姆级指南深夜两点服务器告警铃声突然响起。监控系统显示某台关键业务节点的可用内存正以每小时2%的速度持续下降而top命令却显示用户态进程内存占用稳定。这种看不见的敌人往往最令人头疼——内核态内存泄露正在悄无声息地吞噬系统资源。本文将带你经历一次完整的内核内存泄露狩猎之旅从最初的症状确认到最终的病灶定位手把手教你使用/proc文件系统这把手术刀精准解剖SLAB分配器的内部运作机制。1. 初诊区分用户态与内核态泄露当系统出现内存持续下降时首要任务是确定泄露发生的层级。用户态泄露通常可以通过常规工具快速定位而内核态泄露则需要更专业的诊断手段。以下是关键鉴别步骤# 查看内存整体使用情况 cat /proc/meminfo | grep -E MemTotal|MemFree|Slab典型的内核泄露特征表现为Slab值持续增长特别是SUnreclaim不可回收slab部分MemFree持续下降而用户态进程内存总和通过top查看保持稳定无显著swap使用内核内存通常不会被交换到磁盘对比工具推荐# 使用vmstat观察内存变化趋势 vmstat -SM 5 # 每5秒刷新以MB为单位显示关键指标解读表指标正常情况内核泄露特征Slab平稳波动单调递增SReclaimable占Slab主要部分比例持续降低MemAvailable接近MemFree与MemFree同步下降注意某些文件系统缓存如ext4的inode缓存也会导致Slab增长但这种增长会在内存压力大时自动回收2. 深入探查定位问题slab缓存确认内核泄露后下一步是找出具体哪个slab缓存出了问题。/proc/slabinfo就是我们的显微镜# 按对象数量排序查看slab缓存 cat /proc/slabinfo | awk {if($20) print $1,$2,$3} | sort -k2 -nr | head -20实战技巧时间序列对比法间隔固定时间如1小时采集数据计算各slab的增长量增长速率分析重点关注active_objs与num_objs比值异常的缓存大小分类排查大对象如kmalloc-8192泄露更容易引发明显症状典型问题模式示例kmalloc-8192 36 48 # active_objs持续增长而num_objs不变 dentry 26292 26292 # 两者同步增长可能是正常使用slabinfo关键字段解析字段含义异常表现active_objs活跃对象数持续增长且不与num_objs同步num_objs总对象数突然跃升可能预示泄露objsize对象大小大对象泄露影响更显著3. 高级追踪开启内核调试功能对于确定的嫌疑slab如kmalloc-8192需要更深入的追踪手段# 需要内核编译时开启CONFIG_SLUB_DEBUG echo 1 /sys/kernel/slab/kmalloc-8192/trace然后监控系统日志dmesg -w | grep kmalloc-8192 # 实时查看分配/释放记录调试信息分析要点分配/释放不平衡某些调用路径只有alloc没有free调用栈特征相同代码路径频繁出现时间相关性泄露速率与特定操作同步常用调试命令组合# 统计各调用路径分配次数 cat /sys/kernel/slab/kmalloc-8192/alloc_calls | awk {print $1} | sort | uniq -c | sort -nr4. 实战案例网络模块内存泄露分析以常见的__alloc_skb泄露为例展示完整分析流程确认症状grep kmalloc-8192 /proc/slabinfo watch -n 1 cat /sys/kernel/slab/kmalloc-8192/alloc_calls | wc -l获取调用栈echo 1 /sys/kernel/slab/kmalloc-8192/trace cat /proc/allocinfo alloc_stack.log模式识别# 简单分析脚本示例 from collections import Counter stacks open(alloc_stack.log).read().split(\n\n) counter Counter(stacks) print(counter.most_common(3))代码审查重点skb的kfree_skb调用是否覆盖所有错误路径定时器或工作队列中的skb是否被正确清理引用计数管理是否完备网络内存泄露常见模式错误类型典型表现修复方法未处理错误路径alloc后直接return添加错误处理中的释放循环引用kfree被引用计数阻塞检查引用计数管理定时泄露定期增长的alloc记录检查定时器回调5. 预防与最佳实践建立长效防护机制比事后排查更重要监控方案# 简易监控脚本示例 while true; do date slab_monitor.log cat /proc/meminfo | grep Slab slab_monitor.log awk {print $1,$3-$2} /proc/slabinfo slab_monitor.log sleep 300 done编码规范为所有内核内存分配编写配对释放函数在错误路径中使用goto统一处理资源释放对复杂对象实现dump方法便于调试调试技巧使用kmemleak进行自动化检测在关键函数添加WARN_ON条件检查利用systemtap进行动态探针检测内存泄露排查就像侦探破案需要耐心地收集证据、建立时间线最终锁定真凶。记住最不起眼的线索往往就是突破的关键——那个被我最初忽略的调用栈最终成为了解决三天调试僵局的转折点。

更多文章