☰
Linux内存卡死优化:从swap颠簸到earlyoom的调优实战
2026/10/16 3:32:55 网站建设 项目流程

如果你的Ubuntu电脑或者服务器用着用着突然变成“幻灯片”,鼠标一卡一顿,SSD指示灯狂闪,连切个窗口都要等好几秒,那大概率不是CPU不行,而是内存管理出了问题。接触过Linux一段时间的朋友都知道,Windows卡了可以看任务管理器,Ubuntu卡了却经常让人摸不着头脑——明明内存看起来还有剩余,系统却慢得要死,甚至直接黑屏、死机、远程连不上。这篇内容就是围绕这个痛点来的:我会从Linux内存管理的底层逻辑讲起,用手上实际能跑的命令和参数,逐步把“卡死”这个问题拆开、定位、优化,最终让系统在内存紧张时能自动做出聪明的决策,而不是傻等OOM(Out Of Memory)把整个桌面或者关键进程杀掉。适合被卡死困扰的桌面用户、跑着多服务的服务器管理员,以及想系统搞懂内存参数的新手开发者。

1. 先搞清楚:Linux内存“卡死”到底是怎么发生的

1.1 别再只看任务管理器,先看懂free -h里的数字

很多朋友一遇到卡顿,第一反应是打开系统监视器看CPU占用。结果CPU才30%,内存剩余显示还有2GB,搞不懂为什么机器会慢成那样。这里有第一个常见的误区:Linux的内存占用不能只看“剩余”那一列,因为那只是“没有被任何进程使用”的内存,真正的关键指标是“可用内存(available)”和swap的使用情况。

打开终端执行一次:

free -h

会看到类似下面的输出:

total used free shared buff/cache available Mem: 15Gi 9.6Gi 1.1Gi 1.2Gi 4.6Gi 4.8Gi Swap: 2.0Gi 1.9Gi 91Mi - -

注意看两个地方:一是buff/cache那列占了4.6Gi,这部分是内核用空闲内存做文件缓存和缓冲区,属于“可以随时释放”的,所以available不是简单的 free+swap,而是系统估算的“真正还能分给进程的可用量”。二是Swap的 used 接近2GB,说明系统已经在往硬盘上置换内存页了。如果Swap被大量使用,即使available还有几GB,系统也可能因为磁盘IO瓶颈而卡成PPT。

我在实际使用中发现,Ubuntu默认的swappiness值是60,意味着内核在内存回收时是比较“积极”地倾向于使用swap的,这在物理内存不够用的低端机器上确实能保底,但在内存达到8GB甚至16GB以上的机器上,反而带来了频繁的换入换出,把好好的NVMe盘折腾得够呛。这个参数后面细讲。

1.2 卡死的三位“元凶”:swap颠簸、OOM误杀、缓存误判

根据我踩过的坑,Ubuntu内存卡死基本可以归为三类:swap颠簸、OOM误杀、缓存误判。

第一类,swap颠簸。当物理内存被消费得差不多、内核又希望尽量腾点空间时,会把一些不太活跃的内存页写到swap分区,同时把需要的页读回来。如果系统内存长期处于“差一口气”的状态,就会反复换入换出,搞到整机慢到没法用。这种现象最典型的特征是:内存看起来没用完,磁盘IO却持续打满,尤其机械硬盘上体验极其明显。

第二类,OOM误杀。内核内存压力过大时会启用OOM Killer,挑选一个进程杀掉。问题在于内核的评分逻辑并不总是符合我们的期望,它可能优先杀掉正在跑的训练任务、数据库,甚至桌面环境的某个关键组件,而不是“占内存最多且不重要”的那个浏览器标签页。杀完之后系统可能恢复了,但你的工作也丢了一半。

第三类,缓存误判。上面说的buff/cache看着占据很多内存,其实它不影响进程运行,但会误导初学者的判断和脚本监控。有时候free -h显示已用内存90%以上,但其实系统运行得很好,因为里面大部分是文件缓存,随时可以被回收。真正需要关心的,是available数字和swap使用率。

理解了这三类问题,优化的方向就很清楚了:让内核在“该用swap的时候”才用,让系统在内存耗尽之前有“人为干预”的余地,同时要看清缓存背后的真实内存压力。

2. 动手前先体检:定位内存问题根因的3个命令

2.1 两步确认是“真不够”还是“配置不合理”

不先确诊就乱调参数,是优化的大忌。我曾经在一台内存只有8GB的服务器上直接设置了vm.swappiness=1,结果适得其反——系统内存不够时反而频繁触发OOM,因为swap几乎不怎么用了。所以第一步,必须通过日志和监控数据确认问题类型。

按下面两步走就能快速定位:

  1. 查看内核日志中是否有OOM记录:
sudo dmesg -T | grep -i "out of memory" | tail -20

如果没有任何输出,说明还没到OOM的程度;如果看到类似Out of memory: Killed process 1234 (cupsd)的记录,说明确实发生过内存耗尽。

  1. 观察一段时间内存使用和swap变化:
vmstat 2 15

重点看si(swap in)和so(swap out)两列。如果这两个数字频繁非零,尤其是so那一列几乎不停,就说明系统正在持续地把内存页往磁盘上搬——这就是“swap颠簸”的实锤。si和so都接近0,则大概率不是swap问题,要往其他方向排查,比如某个进程内存泄漏、缓存被异常持有等。

2.2 区分内存压力类型:持续短缺还是瞬时尖峰

还有一种情况是,系统平时内存很充裕,只有某几个特定操作(比如编译大型程序、打开超大的图片、跑机器学习模型)才会瞬间飙升。这时候我们需要搞清楚到底是持续紧缺还是瞬时尖峰,这决定了优化策略完全不同。

最简单的方法是用top或htop观察,在内存飙升时按M键按内存排序,看看是哪个进程在吃内存。也可以用systemd-cgtop查看cgroup层级的内存占用,这在服务器上一眼就能看出哪个服务在“闯祸”。

一个更具体的场景:我在某台跑着三个服务的服务器上遇到卡顿,free -h显示内存还剩不少,但htop里有几个进程的RES数值异常偏大,最后用cat /proc/meminfo发现Shmem:占了好几个GB,才意识到是某个服务挂了共享内存没有释放。

这时候需要记录的其实就两件事:一是消耗大户的名字和内存量,二是它出现的频率。如果把内存消耗按“日常唯一占用大户”删除掉后,系统立刻流畅,说明是应用问题而非系统配置问题,优化思路就不再是调内核参数,而是要限制应用行为或者增加物理资源。

3. 系统级调优:四组sysctl参数让内存管理更聪明

3.1 核心项:swappiness降下来,但别降成零

绝大多数Ubuntu优化教程里都会被提到的一个参数就是vm.swappiness。这个参数控制内核在内存回收时“倾向于使用swap的程度”,范围0到100,默认是60。数值越高,内核越积极地把不常用的内存页换出到swap分区;数值越低,越倾向于回收文件缓存。

我的经验是:对于8GB以上内存、使用SSD的普通环境,设置vm.swappiness=10是一个比较稳妥的起点。10意味着系统在内存压力不大时几乎不动swap,只有当内存真的紧张了才启动换出。即使如此,也不是无脑设小,比如前面提到的8GB物理内存机器,如果swap完全禁用或者swappiness过低,一旦遇到瞬时尖峰,就会直接触发OOM杀进程。

临时生效和永久生效的方法:

# 临时调整,立即生效 sudo sysctl vm.swappiness=10 # 永久写入配置文件 echo 'vm.swappiness=10' | sudo tee -a /etc/sysctl.conf

注意,写入/etc/sysctl.conf后,需要执行sudo sysctl -p或者重启才能生效。

提示:如果物理内存只有4GB甚至更小,不建议强行把swappiness降到10以下,那样会让日常使用频繁触发OOM。在这种情况下,优先考虑加物理内存,或者配置zram(后面会提到)。

3.2 两个容易忽略但影响巨大的参数:vfs_cache_pressure与min_free_kbytes

vm.vfs_cache_pressure控制内核回收目录项(dentry)和索引节点(inode)缓存的速度。默认值是100,表示按正常速率回收;值调高(比如200)表示更积极回收;调低(比如50)表示更倾向保持这些元数据缓存,因为它们对文件操作性能很有帮助。

我一般在文件操作频繁的服务器上设置vm.vfs_cache_pressure=50。因为目录项缓存被提前回收后,下次访问同一目录还要重新读取磁盘元数据,虽然不影响内存“够不够用”,但会让大量小文件操作明显变慢。桌面环境调低一点也有好处,文件管理器打开大目录时会更跟手。

再一个是vm.min_free_kbytes,它表示内存回收时内核希望保留的最小空闲内存量,单位是KB。这个参数直接影响系统在内存紧张时是否还能快速响应。如果这个值太小,可能出现内存都快分光了才想起来回收,导致进程申请内存时出现较长时间的卡顿;如果太大,又会白白浪费内存。

通常建议保留物理内存的1%左右作为min_free_kbytes。比如16GB内存的机器,可以设置256000(约250MB);8GB内存设置约100000(约100MB)。注意不能为了追求“内存全用上”就把这个值设成0,我实测过,设成0以后内核在内存紧张时很容易陷入卡顿甚至休眠式等待。

3.3 让参数开机自动生效:确认配置没白写

sysctl参数往往不是设置完就万事大吉,因为有些内核参数会被系统其他机制覆盖,而且/etc/sysctl.conf在新版Ubuntu上优先级并不总是最高。更可靠的做法是,在/etc/sysctl.d/下单独建一个配置文件:

sudo vim /etc/sysctl.d/99-memory-tuning.conf

内容写入:

vm.swappiness=10 vm.vfs_cache_pressure=50 vm.min_free_kbytes=100000

然后执行:

sudo sysctl --system

这样会按目录顺序加载所有配置,99开头的文件通常最后加载,优先级更有保障。验证的时候用:

sysctl vm.swappiness vm.vfs_cache_pressure vm.min_free_kbytes

如果输出的值和你写入的一致,就说明已经生效。我踩过一次坑:在/etc/sysctl.conf里配了swappiness=1,后来发现每次重启都是60,排查半天才发现是另一个包在/etc/sysctl.d/里也写了一个vm.swappiness=90的配置,把覆盖当成常事了。

4. 加一道自动安全阀:用earlyoom在卡死前止损

4.1 earlyoom的原理:为什么它比内核OOM更“文明”

前面提到,内核自带OOM Killer,但它的触发时机其实很晚——通常在内存耗尽已经发生、系统进入不可用状态之后才动手。想象一下:屋里已经着火了,消防队才出发。kernel OOM的问题就在于它介入太迟,而且挑选进程的标准是基于内核内部的评分,不考虑用户当前正在做什么。

earlyoom的思路是:把“判断是否还有足够可用内存”的动作提前,通过不断读取/proc/meminfo和/proc/loadavg,当可用内存(或swap剩余量)低于设定的阈值,且系统负载过高时,主动杀死占用内存最多的进程。因为它介入得早,杀一个牛进程就能让系统恢复,而不是等到完全卡死再翻车。

它对桌面场景尤其友好。我有一次在笔记本上开着十几个浏览器标签页和一个视频渲染任务,内存以肉眼可见的速度见底,要是没有earlyoom,大概率整机冻结只能按电源键;但配置好earlyoom之后,它会先尝试杀掉占用内存最多的那个标签页进程,桌面还能继续用,顶多提示你某个标签页无响应。

4.2 安装、配置与阈值校准实操

安装很简单:

sudo apt update sudo apt install earlyoom

安装完成之后,它的服务默认是启用的,配置文件在/etc/default/earlyoom。默认阈值是可用内存低于10%时才动手,我实际用下来,在16GB内存的机器上,10%意味着还剩1.6GB,这个阈值触发时系统已经比较卡了,但对大多数情况能兜底。

你可以改成更激进的参数,比如可用内存低于20%就开始留意、低于5%才动手:

sudo vim /etc/default/earlyoom

关键配置项:

EARLYOOM_ARGS="-r 60 -m 20 -s 5"

其中-r 60表示内存剩余低于6%后每60秒检查一次并杀进程;-m 20表示可用内存低于20%启动关注;-s 5表示swap剩余低于5%也启动关注。这里我用的是“关注”而非“立刻杀”——earlyoom默认在第一次达到阈值时不会马上杀,它会先持续观察,如果连续多次仍处于紧张状态才动手。这个机制能避免偶尔一次内存尖峰就误杀进程。

改完配置后重启服务:

sudo systemctl restart earlyoom

验证运行状态:

systemctl status earlyoom

日志里能看到类似这样的输出:

earlyoom[1234]: mem avail: 15 of 16 GiB (93%), swap: 1.9 of 2.0 GiB (95%) earlyoom[1234]: sending SIGTERM to process 5678 (chrome)

看到“sending SIGTERM”就说明它已经替你止损了。

注意:earlyoom杀进程时默认先发SIGTERM,进程友好退出;如果几秒后还没退出,才会发SIGKILL。所以那些能响应SIGTERM的进程(比如浏览器)还有机会保存状态,不至于冷冰冰被干掉。

5. 现代方案组合拳:systemd-oomd与cgroup内存限制

5.1 systemd-oomd:让“吃内存的进程”先被警告再被处理

如果你用的是新版Ubuntu,内核和systemd都比较新,其实还有一个官方血统的选项叫systemd-oomd。它不是额外装一个独立监控程序,而是集成在systemd体系里面,通过监听cgroup的内存压力和swap使用情况来判断是否需要干预,触发时机比earlyoom更“有章法”。

安装和启用:

sudo apt install systemd-oomd sudo systemctl enable --now systemd-oomd

它的配置在/etc/systemd/oomd.conf,关键参数有两个:ManagedOOMMemoryPressureLimit(内存压力阈值,默认50,表示内存压力超过50%时开始关注)和ManagedOOMPreference(优先杀进程的策略)。

不过我个人的使用感受是:systemd-oomd的默认配置比较保守,在内存已经紧张到卡顿的边缘才会介入,很多桌面用户觉得不如earlyoom“灵敏”。所以我的建议是,如果只是桌面防卡死,优先用earlyoom;如果希望在一个较复杂的环境中“软性限制”某个服务的资源,systemd-oomd和cgroup的组合更优雅。

5.2 用MemoryMax限制单个服务的最大内存

在很多场景下,与其等内存耗尽后杀进程,不如提前给某个服务设置内存上限。systemd的cgroup能力提供了两个常用参数:MemoryHigh和MemoryMax。

  • MemoryHigh:软限制,达到这个值后内核会持续对进程施加内存回收压力,但不强制杀。
  • MemoryMax:硬限制,达到后直接OOM Kill该服务,不容商量。

比如我想限制一个容易内存泄漏的web服务,最多只用2GB内存:

sudo systemctl edit my-web-service

在打开的override配置里写入:

[Service] MemoryHigh=1.6G MemoryMax=2G

然后重载服务配置:

sudo systemctl daemon-reload sudo systemctl restart my-web-service

这样如果服务真的内存失控,它会被单独处理,不会拖垮整个系统。来一个交互类比:系统内存就像一个大办公室,cgroup相当于是给每个部门划了工位区,MemoryMax是工位上限,到了上限要么自己走人,要么被保安请走,反正不会挤爆整个办公室。

这个操作在跑数据库或多个Docker容器的机器上价值极高。我有一次在某台服务器上部署了一个爬虫服务,它有个隐藏的内存泄漏,隔几天就把一台机器的swap占满,最后整个机器卡到ssh都连不上。后来用MemoryMax限制到1GB,再也没出过问题——泄漏的服务被反复杀掉重启,而其他服务毫发无损。

6. 常见卡死问题速查与避坑经验

6.1 卡死问题速查表:现象、原因、处理方式

下面把我在实践中遇到最多的问题整理成速查表,方便以后遇到类似现象快速定位:

现象特征可能原因推荐处理方式
系统逐渐变卡,磁盘IO长时间100%swap颠簸,内存在物理内存和swap间反复换入换出调低swappiness;增大物理内存或配置zram;检查大内存进程
突然黑屏或桌面崩溃,重启后日志有OOM记录内存耗尽触发内核OOM Killer安装配置earlyoom提前干预;增加swap空间;限制关键服务内存
free显示used很高,但系统并不卡buff/cache占了很多,属于正常缓存不需要处理;关注available和swap列
某个服务反复被杀,重启又崩溃服务内存泄漏或配置过高用MemoryMax限制单服务内存;修复泄漏源头
开机后一段时间内存占用持续爬升某进程存在内存泄漏用htop按内存排序定位,替换或限制应用

这张表的适用范围很广,无论是桌面环境还是服务器,只要能对上其中一行,按推荐方式处理通常都能见效。

6.2 最后的实操心得:内存优化不是“数字越小越好”

如果把内存优化理解为“尽量多留空闲内存”,那就走进了最大的误区。Linux的设计哲学是“内存不用白不用”,文件缓存该占就占,关键是系统在内存紧张时能迅速做出正确选择。调优的目标是让这个“选择过程”更符合你的使用场景。

我自己的基准配置大致是这样:8GB到16GB内存的机器,swappiness=10,vfs_cache_pressure=50,min_free_kbytes保留约物理内存的1%,再加earlyoom兜底。服务器上会额外给重要服务设置MemoryMax。这套配置跑了很长时间,最直观的改善就是:以前一两周就可能出现一次的卡顿死机,现在基本几个月遇不到一次,而且即使遇到内存尖峰,earlyoom会先动手而不是等内核把桌面干崩。

另外,对内存特别小的笔记本或者旧机器,还有一个很实用的手段:配置zram,把一部分物理内存当作压缩后的swap使用,数据不落盘,压缩比通常在2:1到3:1之间。配置方式不复杂,装好zram-tools后调整/etc/default/zramswap里的ALGO和PERCENT即可。简单来说,它相当于给系统加了一个“虚拟内存增压器”,特别适合内存吃紧但不想牺牲磁盘寿命的场景。

最后说个容易忽略的细节:改完这些参数之后,把/proc/meminfo、free -h、vmstat这几条命令记熟,遇到问题别急着重启,先看数据再下结论。内存优化没有一劳永逸的银弹,但理解了机制之后,至少不会再被卡死问题牵着鼻子走。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询