引言:内存告警不等于物理内存不够

IDC 运维里最容易被"误诊"的告警就是内存。free 一看 available 很低就急着加内存条,结果加了还是告警。这一篇把 Linux 内存的账本彻底算清楚:used 里有多少是缓存、slab 为什么吃掉几个 G、以及 OOM Killer 到底是怎么"点名"的。

一、先看懂 free 输出的每一列

free -h# 关键看 available,而不是 used

available ≈ 真正还能分配出去的内存。它等于 free + 可回收的缓存。所以 used 很高、available 也还健康时,不用慌。判断标准:available 持续低于总内存 10%、或触发 swap 增长,才算内存紧张。

二、第二眼:buff/cache 和 slab 到底是什么

# 查看缓存明细cat /proc/meminfo | grep -E '^(Buffers|Cached|SReclaimable|SUnreclaim|Shmem)'# 查看 slab 占用的内核对象top -bn1 | grep -i slab# 或者用 slabtop 看具体是哪些内核对象slabtop -s c

经典案例:一台机器 Cached 占了 60%,业务方说"内存不够"。实际上这只是 page cache,内核在内存紧张时会自动回收,完全可以忽略。真正要警惕的是 SUnreclaim(不可回收的 slab),如果它持续增长,通常是内核态内存泄漏,比如 dentry/inode 缓存异常或驱动问题。

三、进程内存 RSS 与 VIRT 的坑

# 按物理内存占用排序ps aux --sort=-rss | head -15# 看共享内存占比top -bn1 -o %MEM

VIRT 大不代表占内存。Java/Go 程序 VIRT 经常几十 G,但真正占物理内存的是 RSS,而且 RSS 里还有共享库的部分。定位"谁在吃内存",要看 RSS 减去共享部分,或用 smem 看 PSS。

四、内存泄漏定位三板斧

# 1. 看趋势:连续采样 free 和 meminfowatch -n 5 'free -h; grep -E "SUnreclaim|Slab" /proc/meminfo'# 2. 找进程:RSS 持续增长的进程ps aux --sort=-rss | head -10# 3. 看内核对象:dentry/inode 缓存异常时清一下并观察slabtop -s c | head -20

如果确认是 dentry/inode 缓存异常膨胀,可以临时回收观察:

sync && echo 2 > /proc/sys/vm/drop_caches

但注意:drop_caches 只是症状缓解,不是治疗。回收后 SUnreclaim 再次快速涨回来,说明有内核态泄漏,要查内核版本 bug 或驱动,而不是反复 drop。

五、OOM Killer:谁会被点名

# 查看历史 OOM 记录dmesg -T | grep -i 'out of memory' | tail -20# 或journalctl -k | grep -i 'oom' | tail -20

OOM Killer 的评分规则核心是 oom_score:进程占的内存越多分越高,越容易被杀;root 进程有 3% 的加分豁免;还可以通过 oom_score_adj 手动调整。

# 查看进程的 oom 分数cat /proc//oom_score# 保护关键进程(MySQL/Redis 等),降低被杀概率echo -1000 > /proc//oom_score_adj# 永久生效:写入 systemd unit 或 sysctl 脚本

实战建议:数据库、Redis 这类核心进程统一设置 oom_score_adj=-500 到 -1000,避免业务高峰时被误杀;同时给关键服务配 systemd 的 Restart=on-failure,被杀后自动拉起。

六、Swap 的正确打开方式

# 查看当前 swap 使用cat /proc/sys/vm/swappiness# 调整为更保守的 10(优先用物理内存)sysctl -w vm.swappiness=10# 永久生效echo 'vm.swappiness=10' >> /etc/sysctl.conf

判断标准:si/so 持续大于 0 说明在频繁换入换出,内存是真的紧张,需要扩容或优化业务;偶尔一次 swap 不用紧张。ssd 上 swap 的"缓冲"作用可以保留,但 swappiness 建议调低。

七、排查决策树总结

  • available 充足 + used 高 → 缓存占位,忽略
  • available 低 + SUnreclaim 涨 → 内核态泄漏,查驱动/内核版本
  • available 低 + 某进程 RSS 涨 → 应用泄漏,上 profiler(如 pprof/jmap)
  • 出现 OOM 记录 → 检查 oom_score_adj 与 swap 配置,先止损再根治

记住一句话:内存告警先看 available,再查 slab,最后才轮到加内存条。