人人都会AI编程

21.2 内存优化:页缓存调优、Swap 策略、OOM 阈值调整

更新时间:2026-07-12

内存管理对系统性能的影响常常被低估。Linux 习惯将空闲内存用作页缓存(page cache)来加速磁盘读写,当内存紧张时又会依赖 Swap 和 OOM Killer 来“解围”。理解并适当调整这三者,就能用有限的资源换取更平稳的服务表现。

1. 页缓存调优:让常用数据留在内存里

页缓存是 Linux 内存使用中占比通常最大的一块。每当进程读取文件,内核就会把文件内容缓存在未使用的内存中,下次再读时可以直接命中缓存,从而避免缓慢的磁盘 I/O。free 命令中 buff/cache 那一列指的就是这一类使用。

原理上,页缓存总是在有剩余内存时自动增长,在有新需求时自动回收。一般不需要人工干预,但在某些场景下手动干预能防止性能抖动:

  • 控制缓存回收的激进程度

内核参数 vm.vfs_cache_pressure 用于调整内核回收目录项和 inode 缓存的倾向。默认值 100,数值越小,内核越不情愿回收这类缓存,适合于文件系统操作繁重的场景(例如大量读取小文件的文件服务器)。建议可调至 50。

  • 优先释放可回收缓存

在内存紧张前主动写出脏页并释放干净的缓存,避免突发 I/O。可以通过 echo 1 > /proc/sys/vm/drop_caches 释放页缓存(1 释放页缓存,2 释放 dentry 和 inode 缓存,3 全部释放)。注意:这是非破坏性操作,只在需要立即腾出内存供测试或解决临时压力时使用,不要写入自动化脚本,因为正常缓存会自动回收,人工释放反而可能影响性能。

  • 监控页缓存命中率

使用 cachestat(来自 perf-tools 或 bcc-tools)或 sar -B 可以观察缓存命中/未命中的次数和比例。如果持续出现高未命中,说明内存不足以容纳常用工作集,可能需要增加内存或减少进程占用。

2. Swap 策略:用交换空间换取稳定,而不是灾难

Swap 是当内存不足时将不常用的匿名页(进程数据)交换到磁盘的机制。很多人错误地认为“禁用 Swap 可以提升性能”,但正确配置的 Swap 能为系统提供缓冲,避免 OOM Killer 突然杀死关键进程。

核心参数vm.swappiness,取值范围 0–100,默认 60。它控制内核回收匿名页(换出到 Swap)和回收文件页缓存之间的倾向:

  • 值越高,越积极使用 Swap;
  • 值越低,倾向于先回收文件缓存。

推荐策略

  • 服务器或数据库:设置较低值,如 10–20。让系统尽量用缓存加速 I/O,只有在内存确实紧张时才使用 Swap,避免无谓的磁盘交换影响响应时间。
  • 桌面或交互式系统:保留默认值或略提高(60 或更高),使未使用的后台程序更早换出,为前台应用留出急用内存。
  • 绝对禁用 Swap 要三思:除非物理内存极大(远超过工作集大小),否则禁用 Swap 会在内存用尽时直接触发 OOM Kill,没有任何缓冲。更好的做法是保留至少 2GB 以上的 Swap 空间,无论物理内存有多大,因为总有一些长期未访问的匿名页可以被安全换出。

其他有用参数

  • vm.vfs_cache_pressure(见上节)与 Swap 有一定关联:适当降低该值可减少缓存回收带来的性能波动。
  • vm.min_free_kbytes:保留给紧急分配的最小内存量(KiB)。增大该值(如从默认的 4MB 提升到 128MB)可为突发申请留出缓冲,降低快速触发 OOM 的概率。

查看当前 Swap 使用情况:free -hswapon --show;实时观察换入换出速率:vmstat 1si/so 列。

3. OOM 阈值调整:保护关键任务不被误杀

当物理内存和 Swap 全部耗尽,内核的 Out-Of-Memory Killer 会选择一个进程发送 SIGKILL 以腾出空间。默认的“坏账评分”基于进程占用内存(oom_score),占用越多越可能被杀。你可以通过调整 oom_score_adj 来影响这个选择。

  • 查看某个进程的 OOM 评分(越高越危险):
  cat /proc/<PID>/oom_score
  
  • 调整进程的 OOM 忍受度:

/proc/<PID>/oom_score_adj 可写入 -1000 到 1000。
-1000 表示完全免除被 OOM Killer 选择;
1000 表示强烈倾向杀掉该进程。

  • 保护核心服务

对于数据库(如 mysqld)、sshd 等守护进程,将其 oom_score_adj 设置为 -500 或 -1000,避免在内存紧张时被杀。可以在 systemd unit 文件中使用 OOMScoreAdjust=-500 来声明。

  • 主动牺牲非关键进程

对于批处理任务或可重试的后台脚本,可以设置较高的正 adjustment(如 500),让它们在内存危机时首当其冲。

  • 辅助参数
  • vm.panic_on_oom:设为 1 后,当 OOM 触发时内核直接 panic,重启整个系统而不是杀进程。适合某些嵌入式系统或需要完整保护数据一致性的环境,普通服务器不要开启。
  • vm.oom_kill_allocating_task:设为 1 时,直接杀死触发 OOM 的那个进程,而不做复杂的评分选择。对于某些场景(如容器)可能更可预测。

实用检查命令

# 查看最近 OOM 记录
dmesg | grep -i "out of memory"
# 查看某个服务的 oom_score 和调整值
cat /proc/$(pgrep sshd)/oom_score
cat /proc/$(pgrep sshd)/oom_score_adj

综合建议

在实际运维中,内存优化遵循“先观测、后调整”的原则:

  1. 通过 htopfreevmstatsar 建立内存压力基线;
  2. 为 Swap 保留适当空间并合理设置 swappiness;
  3. 通过 oom_score_adj 给关键服务“免死金牌”;
  4. 仅在确认缓存回收策略影响生产性能时才微调 vfs_cache_pressure

这些参数配合使用,能让 Linux 在内存接近枯竭时保持冷静,优先放弃可以再生的缓存,而不是杀死你正在运行的业务。