3、Linux内存管理:内存分配与回收、OOM Killer机制、Swap分区与交换空间

聊到Linux内存管理,很多运维同学第一反应就是「看free -m」。嗯,这没错,但远远不够。我做了这么多年监控,发现内存相关的故障其实是最隐蔽的——它不像CPU飙高那么明显,也不像磁盘IO那么吵闹。内存问题往往是「温水煮青蛙」,等你发现时,业务已经抖了好一阵了。

这一章,我们就把Linux内存管理的几个核心机制掰开揉碎。你搞懂了这些,搭建监控告警体系时才知道该盯什么、怎么盯。

3.1 内存分配:不是你要,我就给

Linux的内存分配策略,说白了就是「乐观分配」。进程申请内存时,内核通常直接说「好,给你」,然后记个账。但实际物理内存并没有真正划过去。

这种机制叫 Overcommit(过度分配)。为什么这么干?因为大多数进程申请的内存根本用不完。你想想看,你开个Java应用,-Xmx设了4G,但平时可能只用几百兆。如果内核非得实打实给你预留4G物理内存,那服务器很快就得「内存荒」。

我个人习惯把Overcommit分为三个等级,通过 vm.overcommit_memory 控制:

策略 说明
0 启发式 内核自己判断,能过就过。默认值,大部分场景够用
1 总是允许 来者不拒。适合跑内存密集型计算任务
2 禁止超过比例 严格限制,超过 overcommit_ratio 就拒绝
我的建议:生产环境别用默认值0。我遇到过几次因为Overcommit导致的内存黑洞——进程申请成功,但实际分配时发现不够,直接触发OOM。我个人习惯设成2,然后根据业务调整ratio。

3.2 内存回收:内核的「保洁阿姨」

内存不够了怎么办?内核会启动回收机制。这里有两个关键角色:kswapddirect reclaim

kswapd是个后台线程,它像保洁阿姨一样,看到内存快不够了就提前打扫。它有两个水位线:

  • pages_low:低水位,kswapd开始干活
  • pages_min:最小水位,再低就要出大事了
  • pages_high:高水位,kswapd可以歇着了

为什么会这样?因为kswapd回收内存需要时间。如果它回收的速度赶不上进程申请的速度,那就会触发 direct reclaim——进程自己动手回收内存。这时候,进程会被阻塞,性能直接跳水。

监控要点:你在监控系统里看到 /proc/vmstat 中的 pgsteal_kswapdpgsteal_direct 持续增长,尤其是direct reclaim占比过高,说明内存压力已经很大了。我曾经在线上看到direct reclaim占比超过30%,那台机器的业务延迟直接翻倍。

3.3 OOM Killer:最后的「清道夫」

当内存彻底不够,回收也救不了时,OOM Killer就登场了。它会挑一个进程杀掉,释放内存。

但问题来了——它杀谁?

内核有一套评分机制,叫 oom_score。评分越高,越容易被杀。主要看这几个因素:

  • 进程占用的内存大小(越大越危险)
  • 进程的存活时间(越短越容易被杀)
  • 进程的优先级(nice值越低越安全)
  • 进程的 oom_score_adj 调整值

你可以通过 /proc/[pid]/oom_score 查看每个进程的评分。我建议你在搭建监控时,把这个指标也采集上来。万一哪天OOM了,你能快速定位到「为什么是它被杀了」。

避坑指南:我曾经遇到一个案例,MySQL主库被OOM Killer干掉了。查了半天,发现是因为一台监控采集器占用了大量内存,而MySQL的 oom_score_adj 没调低。从那以后,我养成了习惯——所有核心数据库进程,都设置 echo -1000 > /proc/[pid]/oom_score_adj,让内核尽量别碰它们。

3.4 Swap分区与交换空间:内存的「备胎」

Swap,说白了就是把磁盘当内存用。当物理内存不够时,内核会把不常用的内存页换到磁盘上。

但这里有个大坑——Swap不是越多越好。我见过很多运维同学,服务器配了64G内存,还搞个128G的Swap。嗯,这其实是在给自己挖坑。

为什么?因为磁盘IO比内存慢几个数量级。一旦开始大量使用Swap,应用的响应时间会从毫秒级变成秒级。你想想看,一个Web请求等几秒才返回,用户早跑了。

控制Swap行为的关键参数是 vm.swappiness

行为
0 尽量不用Swap,除非内存彻底不够
10 我常用的值,仅在内存紧张时使用Swap
60 默认值,内核会相对积极地使用Swap
100 非常积极,几乎把内存当缓存用
我的经验:对于数据库、缓存这类对延迟敏感的应用,我建议把swappiness设成0或10。对于普通的Web服务器,10-30就够用了。别设成0就万事大吉了——极端情况下内存耗尽,系统还是会强制使用Swap。

3.5 监控实战:该盯哪些指标?

好了,理论讲完了。咱们来点实际的——搭建内存监控告警时,该盯哪些指标?

我个人习惯把指标分成三个层级:

  1. 基础指标:总内存、已用内存、可用内存、Swap使用量。这些用 free -m 就能看到。
  2. 压力指标/proc/vmstat 中的 pgsteal_*pgscan_*pgfault。这些能反映内存回收的压力。
  3. 风险指标:OOM Killer的触发次数(dmesg | grep -i "oom")、进程的oom_score。这些是「最后防线」的预警。

告警阈值建议:

  • 可用内存低于总内存的10% → 警告
  • Swap使用率超过50% → 警告(说明内存压力已经传导到磁盘了)
  • direct reclaim占比超过10% → 严重告警
  • 出现OOM Killer事件 → 紧急告警,立即处理

嗯,这一章的内容就到这里。你把这些机制搞清楚了,搭建内存监控告警体系时就不会「眉毛胡子一把抓」了。下一章,我们聊聊CPU的监控——那个更刺激,因为CPU问题往往来得更突然。