Linux内存不断升高的排查思路

admin 2026-01-05 18:00:38 网络安全文章 来源:ZONE.CI 全球网 0 阅读模式

文章总结: 针对Linux内存持续升高但top无明确占用的问题,文档提供了系统排查思路。原因可能包括内核Slab泄漏、驱动、短命进程或用户态泄漏。建议先用free确认available下降,通过slabtop和/proc/meminfo重点监控SUnreclaim排查内核问题;利用smem和atop分析进程PSS及增长;结合dmesg查看日志,用execsnoop捕捉短命进程,必要时使用perf或kmemleak深度定位。 综合评分: 95 文章分类: 实战经验


cover_image

Linux内存不断升高的排查思路

原创

刘军军

运维星火燎原

2026年1月4日 22:49 山西

当top/htop没有明显指向罪魁祸首时。以下是一套系统性的排查方法,帮助你找到“隐藏”的内存消耗者:

核心思路: 内存消耗不一定直接体现在某个用户态进程的RES或%MEM上。它可能来源于:

  1. 内核本身: 内核数据结构(如slab缓存、页表、网络缓冲区等)泄漏或过度增长。
  2. 内核模块/驱动: 某个加载的内核模块(尤其是硬件驱动)存在内存泄漏。
  3. 短命进程: 频繁启动又退出的进程,在top的刷新间隙难以捕捉。
  4. 缓存/缓冲区的变化: 虽然free显示available低,但Linux会积极利用内存做缓存和缓冲,这部分在free命令里属于buff/cache,当应用程序需要时会被回收。但如果available持续降低且free也很低,说明缓存/缓冲不是主因,而是有真实占用。
  5. 内存泄漏的用户态进程: 进程的内存泄漏可能分散在虚拟地址空间的各个角落,top显示的RES可能增长缓慢或不明显,但VIRT可能很高,或者其占用的共享库、tmpfs等有异常。

排查步骤与方法:

一、 精确分析内存分布(free命令的深入解读)

1.free -h / free -m (多次运行观察趋势):

  • 重点关注 available 列。这是系统认为真正可用给应用程序的内存(≈ free + buff/cache 中可回收的部分)。如果它持续下降,说明有真实的内存被占用且无法被简单回收。
  • 观察 buff/cache:如果它很大但 available 也还充足,通常是正常现象(系统利用空闲内存加速IO)。如果 available 很低而 buff/cache 很大,尝试手动释放:sync; echo 3 > /proc/sys/vm/drop_caches (需要root)。操作后观察 available 是否显著回升。如果回升有限,说明主要问题不是缓存/缓冲区,而是其他占用。
  • 观察 used 和 free:free 很低是警示信号,但结合 available 和 buff/cache 看更有意义。

二、 深入内核层面:Slab分配器与内存统计

1.slabtop (需要root):

  • 这是最关键的工具之一!它显示内核slab分配器的缓存使用情况。slab用于管理内核对象(如inodecache, dentry, skbuffheadcache, vmarea_struct等)。
  • 运行 sudo slabtop -s c (按缓存大小降序排序)。
  • 重点观察: 哪个Cache名称占用的OBJS数量和SIZE异常巨大?特别关注那些持续增长的项。例如,dentry或inode_cache异常高可能表示文件系统元数据缓存泄露;网络相关的skbuff高可能表示网络问题;驱动相关的模块名出现且增长也要注意。
  • 记录下可疑的Cache名称。

2.cat /proc/meminfo (详细内存分项统计):

  • 这个文件提供了极其详细的内存使用分类。运行 cat /proc/meminfo 并重点关注以下项:

  • Slab: 总Slab使用量 (应与slabtop的总和对应)。

  • SReclaimable: 可回收的Slab (如dentry, inode cache)。

  • SUnreclaim: 不可回收的Slab。这个值持续增长是内核或驱动内存泄漏的强烈信号!

  • PageTables: 页表占用。如果系统运行了大量进程或使用了大量内存映射,可能会很高。

  • KernelStack: 内核栈占用。每个线程消耗一点。

  • VmallocUsed: 通过vmalloc分配的内核空间。某些驱动或模块会使用。

  • HugePages_: 大页相关统计(如果启用了)。

  • Mapped: 文件映射占用的内存。

  • AnonPages: 匿名页(如进程堆、栈)。

  • Buffers: 原始块设备缓存。

  • Cached: 页缓存(文件内容缓存)。

  • SwapCached: 换出过但又换回的内存,仍在swap缓存中。

  • Active(file)/Inactive(file): 活跃/不活跃的文件缓存。

  • Active(anon)/Inactive(anon): 活跃/不活跃的匿名内存。

  • Unevictable: 无法换出的内存(如mlock的或某些shm)。

  • Committed_AS: 当前所有进程已申请的虚拟内存总量(可能超过物理内存+交换空间)。

  • 方法: 定期(如每隔几分钟)运行 cat /proc/meminfo | egrep ‘Slab|SReclaimable|SUnreclaim|PageTables|KernelStack|VmallocUsed|Committed_AS’ 并记录值,观察哪些项在持续增长。SUnreclaim的增长是最危险的。

三、 进程级深度分析(超越top)

1.ps 命令组合:

  • 按内存排序: ps -eo pid,ppid,user,%mem,%cpu,rss,vsz,cmd –sort=-%mem | head -n 20 或 ps -eo pid,ppid,user,%mem,%cpu,rss,vsz,cmd –sort=-rss | head -n 20。查看RSS(常驻内存)或%MEM最高的进程。虽然top也做这个,但ps的输出格式可能更易分析历史记录或脚本处理。
  • 按虚拟内存排序: ps -eo pid,ppid,user,%mem,%cpu,rss,vsz,cmd –sort=-vsz | head -n 20。高VSZ(虚拟内存)可能指示内存泄漏但尚未完全提交物理页的进程,或者使用了大量共享库/映射文件的进程。

2.smem 工具 (推荐安装):

  • smem 提供了更智能的内存报告,特别是它能区分独占内存(USS) 和比例集大小(PSS)。PSS更公平地计算了共享库的内存占用(将共享内存按使用进程数均摊)。

  • 安装:sudo apt install smem (Ubuntu/Debian系麒麟) 或 sudo yum install smem (CentOS/RHEL系麒麟)。

  • 使用:

  • sudo smem -s pss -r: 按PSS降序排序,最公平。

  • sudo smem -s uss -r: 按USS降序排序,看独占内存。

  • sudo smem -t -k: 带总计的表格输出,单位KB。

优势: 能更准确地找出真正消耗物理内存的进程,尤其是那些共享库很多的进程。

3.atop 工具 (强烈推荐安装):

  • atop 是一个强大的交互式性能监控工具,功能远超top。它能记录历史数据,并提供更详细的进程级内存统计(包括进程占用的PSS、RSZ、VSZ,以及进程使用的页表大小等)。

  • 安装:sudo apt install atop 或 sudo yum install atop。

  • 使用:

  • 运行 sudo atop。

  • 按 m 键切换到内存视图。观察各列。

  • 特别关注 MEM 列下的 RSS (类似top的RES), PSS (更公平), VGROW (虚拟内存增长量), RGROW (常驻内存增长量)。VGROW/RGROW高的进程即使当前绝对值不高,也值得怀疑。

  • 按 c 切回进程视图,按 d 可以显示磁盘,按 n 显示网络。

  • atop 默认会记录历史(通常每天一个日志文件在/var/log/atop),可以回放分析:atop -r /var/log/atop/atop_YYYYMMDD (按 t 前进)。

4.检查短命进程:

  • auditd 系统: 如果系统启用了auditd,可以尝试配置规则记录所有进程执行(生产环境慎用,日志量巨大):
sudo auditctl -aexit,always -F arch=b64 -S execve
sudo auditctl -aexit,always -F arch=b32 -S execve

然后分析 /var/log/audit/audit.log,查找频繁执行的命令。

  • sysdig/csysdig 工具: 非常强大的动态追踪工具,可以实时捕获所有系统调用和事件。

  • 安装:参考官网或发行版仓库。

  • 实时捕获进程执行:sudo sysdig “proc.name != ”” 或 sudo csysdig (交互式界面,按 F2 选择视图)。

  • execsnoop (来自bcc/bpftrace工具集): 专门设计来追踪短命进程。需要安装bpfcc-tools或bpftrace。

sudo execsnoop-bpfcc  # 或 sudo execsnoop (取决于包名)

四、 系统日志与内核信息

1.dmesg / journalctl:

  • 检查内核环形缓冲区日志:dmesg -T | tail -n 100 或 dmesg -T –level=err,warn。特别留意是否有 Out of memory: Kill process … (OOM killer) 信息、slab分配失败、驱动加载/卸载错误、硬件错误等。
  • 使用journalctl查看系统日志:sudo journalctl -b 0 –since “1 hour ago” -p 3 (查看本次启动以来,优先级为error及以上的日志,时间范围最近1小时)。调整时间范围和优先级过滤。

2.检查内核模块:

  • 列出加载的模块:lsmod。
  • 结合/proc/meminfo中的SUnreclaim增长和slabtop中发现的异常缓存项,怀疑特定驱动模块。可以尝试谨慎地卸载最近加载的、非关键的可疑模块(sudo modprobe -r ),观察内存增长是否停止。卸载驱动有风险,可能导致硬件失效或系统不稳定! 最好在测试环境或确定模块可卸载时操作。

五、 高级追踪(需要一定专业知识)

1.perf 工具:

  • 使用perf追踪内存分配事件(需要调试符号):
sudoperfrecord-ekmem:kmalloc-ekmem:kfree-ekmem:kmem_cache_alloc-ekmem:kmem_cache_free-ag
# 运行一段时间后 Ctrl+C
sudoperfreport

分析报告,看哪些内核函数分配了大量内存且没有释放。

2.kmemleak (内核配置):

  • 如果麒麟系统内核编译时启用了CONFIGDEBUGKMEMLEAK,这是一个专门检测内核内存泄漏的机制。需要挂载debugfs,然后:
echo scan > /sys/kernel/debug/kmemleak  # 触发扫描
cat /sys/kernel/debug/kmemleak          # 查看可能的泄漏点报告
  • 这个功能通常用于开发调试,生产内核可能未启用。

总结与建议步骤:

  1. 确认问题: 持续运行 free -h 或 watch -n 5 “free -h; echo; date”,明确available内存确实在持续下降,且手动drop_caches后回收有限。
  2. 内核嫌疑: 立即使用 sudo slabtop -s c 和 watch -n 5 “cat /proc/meminfo | egrep ‘Slab|SReclaimable|SUnreclaim|Committed_AS'”。如果SUnreclaim持续增长,高度怀疑内核或驱动泄漏。 记录slabtop中增长最快的缓存项。
  3. 进程再排查: 安装并使用 smem -s pss -r 和 sudo atop (重点看PSS, VGROW, RGROW)。这些工具比top更能揭示真实内存消耗。
  4. 日志检查: 仔细查看 dmesg -T 和 sudo journalctl -b 0 –since “yesterday” -p 3 中的错误、警告和OOM信息。
  5. 短命进程: 如果怀疑,使用 execsnoop 或 sysdig 进行捕捉。
  6. 驱动/模块: 根据slabtop和日志线索,检查lsmod,在充分评估风险后尝试卸载可疑的非关键驱动模块。
  7. 高级诊断: 如果上述步骤仍无头绪,考虑使用perf追踪内存分配,或检查内核是否支持kmemleak。

重要提示:

  • 备份: 在进行可能影响系统稳定性的操作(如卸载模块)前,确保有备份或能在物理接触机器。
  • 环境: 如果是生产环境,操作需格外谨慎,尽量在业务低峰期进行,并做好回滚准备。
  • 持续监控: 使用atop记录历史或编写脚本定期捕获/proc/meminfo和slabtop输出,便于分析增长趋势。

免责声明:

本文所载程序、技术方法仅面向合法合规的安全研究与教学场景,旨在提升网络安全防护能力,具有明确的技术研究属性。

任何单位或个人未经授权,将本文内容用于攻击、破坏等非法用途的,由此引发的全部法律责任、民事赔偿及连带责任,均由行为人独立承担,本站不承担任何连带责任。

本站内容均为技术交流与知识分享目的发布,若存在版权侵权或其他异议,请通过邮件联系处理,具体联系方式可点击页面上方的联系我

本文转载自:运维星火燎原 刘军军《Linux内存不断升高的排查思路》

评论:0   参与:  0