Linux系统的内存性能问题通常不在物理容量本身,而在内核如何分配、回收和换出页面。理解这些机制后,我们可以通过参数调整和监控手段显著降低延迟、避免卡顿。下面先介绍基础概念,再给出具体优化做法。

一、Linux内存分配与回收的基本原理
Linux内核将物理内存划分为多个区域,其中大部分用户进程使用的内存分为匿名页(anonymous pages,如堆、栈)和文件缓存页(page cache,如读取文件后的缓存)。文件缓存页在内存紧张时可以直接释放,因为磁盘上有副本;匿名页若未映射到文件,则必须写入swap才能回收。这种区分决定了调优的核心思路:尽量保留匿名页、合理释放文件缓存。
内核通过kswapd后台线程在内存水位低于阈值时异步回收,而当分配请求到来却发现空闲内存不足时,会触发直接回收(direct reclaim),此时当前进程被阻塞,造成明显的延迟。另一个关键组件是oom_killer,当系统实在无法回收出内存时,它会根据每个进程的oom_score选择得分最高的进程杀掉以保住系统。很多误杀问题的根源,就是对打分规则不了解。
1.1 查看当前内存真实使用情况
新手常只看free -m的used列,其实应该关注available列。available估算了可回收的缓存加上空闲内存,更能反映压力。我们可以用下面命令观察:
# 查看内存概览,重点看available free -h # 查看详细内存组成与回收状态 cat /proc/meminfo # 观察哪些进程占用匿名内存最多 ps -eo pid,comm,vsz,rss,oom_score | sort -k5 -nr | head
上述输出中,RSS是实际物理占用,VSZ是虚拟大小。oom_score由内核计算,数值越大越容易被杀。我们可以写个简单脚本定期记录,定位泄漏源。
二、通过sysctl调整交换与回收行为
最常用的参数是vm.swappiness,取值范围0到100,表示内核倾向于换出匿名页的程度。默认值通常是60,对桌面尚可,但对延迟敏感的服务端往往偏高。将其降到10或更低,可以让内核优先回收文件缓存,减少swap写入带来的磁盘IO。
但要注意,设为0并不代表禁用swap,只是极端情况下才换出。完全关闭swap分区反而危险:当内存真正耗尽,内核无法换出匿名页,直接回收失败后会更快触发oom_killer。因此建议保留swap但调低swappiness,并配合vm.vfs_cache_pressure调整目录项缓存回收优先级。
2.1 临时与永久修改参数
临时修改可用sysctl命令,重启失效;永久修改写入/etc/sysctl.conf或使用systemd的sysctl服务。示例如下:
# 临时将swappiness设为10 sysctl -w vm.swappiness=10 # 临时提高目录缓存回收倾向(默认100,设大表示更积极回收dentry/inode) sysctl -w vm.vfs_cache_pressure=150 # 永久生效,编辑/etc/sysctl.d/99-memory.conf cat > /etc/sysctl.d/99-memory.conf <<'EOF' vm.swappiness=10 vm.vfs_cache_pressure=150 vm.min_free_kbytes=65536 EOF # 加载配置 sysctl --system
vm.min_free_kbytes预留少量内存给内核自己用,避免突发分配时直接回收。设置过大浪费内存,过小则效果不明显,一般按总内存的1%到3%取。
三、使用cgroup限制异常进程内存
如果某服务有内存泄漏倾向,与其等它拖垮整机,不如用cgroup v2把它框住。cgroup能限制一组进程的最大内存,超出后触发该组的oom而非全局oom。下面以systemd单元为例,限制某个服务最多用2G。
# 在systemd service文件中添加 [Service] MemoryMax=2G MemoryHigh=1.5G TasksMax=512
其中MemoryHigh是软上限,超过后会积极回收;MemoryMax是硬上限,突破即杀进程。这样即便程序bug导致膨胀,也不会影响同机其他业务。如果是非systemd场景,可直接写cgroupfs:
# 创建cgroup并限制 mkdir /sys/fs/cgroup/mysvc echo 2147483648 > /sys/fs/cgroup/mysvc/memory.max echo $$ > /sys/fs/cgroup/mysvc/cgroup.procs # 之后该shell及子进程受限于2G
这种隔离比调整全局参数更精准,也是容器技术的底层基础。生产环境应优先用cgroup而非依赖oom_killer全局兜底。
四、避坑与监控建议
一个常见误区是看到swap被用了一点就认为内存不足,其实那可能是系统闲置时kswapd换出的冷数据。只要si/so(swap in/out)在sar或vmstat里长期为0,就不用紧张。另一个坑是过度依赖drop_caches手动清缓存,这只会短暂释放,还可能导致后续读盘变慢,不如交给内核自动管理。
监控上建议部署node_exporter配合Grafana,重点看node_memory_MemAvailable_bytes、swap_io趋势和oom事件日志。当available低于总内存10%并持续,就该排查泄漏而非简单重启。调优是持续过程,结合业务峰值压测才能找到合适参数。
4.1 简单监控脚本示例
下面脚本每分钟记录一次可用内存与swap使用,便于回溯:
#!/bin/bash
while true; do
avail=$(awk '/MemAvailable/{print $2}' /proc/meminfo)
swap=$(awk '/SwapTotal/{t=$2} /SwapFree/{f=$2} END{print t-f}' /proc/meminfo)
date=$(date '+%F %T')
echo "$date avail_kb=$avail swap_used_kb=$swap" >> /var/log/mem_mon.log
sleep 60
done
通过该日志能清楚看到内存拐点,配合前文sysctl与cgroup手段,基本可让Linux在有限硬件下维持稳定高性能。
Linux内存管理swap调优oom_killer修改时间:2026-08-06 04:09:31