资讯动态

Ubuntu卡死原因与内存优化实践:从内核参数到zram调优指南

发布时间:2026/10/16 23:12:01 来源:尧图企业网站定制
Ubuntu用着用着突然卡死鼠标像陷入泥潭切个窗口都要等好几秒最后只能长按电源键强行断电。这个场景我太熟了——最早我以为是内存条挂了换内存、换主板、换硬盘都试过问题依旧。后来才想明白绝大多数情况下Ubuntu默认的内存管理策略在桌面场景里并不算合理缺的不是内存本身而是“该回收回收、该交换交换”这一整套机制的调教。这篇文章我会从内存管理的底层逻辑讲起再一步步给出可复制、可验证的排查命令和优化参数最后把zram、zswap、systemd-oomd这些能真正提升体验的方案按适用场景拆开讲清楚。不管你是被Ubuntu卡死折磨的桌面用户还是负责一堆Linux服务器的运维同学这篇都值得花十分钟读完并备份到自己常用的运维笔记里。1. Ubuntu卡死不是玄学内存机制里藏着真正的元凶1.1 空闲内存被“借走”是特性但没人还回来就是灾难很多人第一次用Ubuntu时都会打开系统监视器然后发现内存占用常年接近90%哪怕你只开了一个浏览器。这其实是Linux的一个经典设计内核会把空闲内存尽可能拿去做文件缓存、目录缓存和缓冲用来加速磁盘读改写。这部分内存在free命令里被标记为buff/cache逻辑上属于“可以回收”而非“已占用”。问题就出在这个“可以回收”上。桌面负载和服务器负载完全不同你开着浏览器、文档工具、代码编辑器来回切换时会不断产生新的文件缓存和匿名内存页。当物理内存接近耗尽内核开始回收缓存时如果回收速度跟不上分配速度系统就会出现肉眼可见的卡顿。更麻烦的是很多桌面用户根本没有配置可用的交换空间或者把/swapfile建得特别小于是内核回收无路可退只能走直接回收路径这时候整个系统的停顿会非常剧烈。我用一个厨房的类比来解释为什么这会“卡死”Linux把空闲内存当作台面上提前切好的菜缓存做菜时不够地方可以随时把菜收进冰箱。问题是这个冰箱swap如果是空的或者小得可怜那菜就没地方收厨师只能边切边做手忙脚乱。这时候你喊破喉咙系统也只能优先保住内核自己剩下的进程一起遭殃。1.2 内存不足时的连锁反应从卡顿到OOM当物理内存和交换空间全部吃紧内核会启动oom_killer去杀掉一些进程来释放内存。这个杀手并不智能它主要根据进程的内存占用和oom_score来选“牺牲品”你正在写代码的IDE、没保存的文档都有可能被它选中。更让人恼火的是等到oom_killer动手时整个系统通常已经进入半死状态你连看一眼是谁被杀的机会都没有。而且还有一个隐藏的恶性循环如果交换空间位于机械硬盘或者SSD已经接近装满内核把内存页换出的速度极慢而进程还在疯狂申请内存这时候你会看到整个系统几乎“冻结”硬盘灯狂闪鼠标动不了按键盘没反应——其实内核还在后台拼命干活只是它的力气全花在换页上了。所以Ubuntu内存优化这件事核心不是“让我多用点内存”而是“让内存管理系统在压力到来时有合理的路径可走”。理解了这一点接下来所有的排查和调参才有意义。2. 先搞清楚谁在吃内存一套可复制的排查链路2.1 别只会看free -h这几个数字要知道怎么读优化的第一步永远是量化现状。打开终端跑free -h很多人只知道看used这一列其实最关键的是available。看下面这个示例输出只是参考实际数值因机器而异total used free shared buff/cache available Mem: 31Gi 4.1Gi 6.8Gi 412Mi 20Gi 25Gi Swap: 2.0Gi 0B 2.0Gi这里available才是系统实际“还能给新程序用”的内存free只是完全没被占用的物理页buff/cache里的很大一部分能随时回收。如果你的available经常被压到只有几百MB甚至趋近于零而buff/cache却居高不下恭喜你这正是优化空间最大的情况。MemAvailable这个数值在内核里是估算出来的它会考虑剩余空闲页、可回收的缓存以及swap剩余量。日常判断系统是不是“要出事”看available比看free准得多。2.2 用vmstat和ps判断系统是不是在疯狂换页free只能看到快照想看系统是不是“正在狂换页”用vmstat 1持续刷几秒vmstat 1重点关注最后一列si和so它们分别表示每秒从swap换入和换出的内存量。如果这两个数值长期很高比如几百MB甚至上GB说明系统一直在倒腾内存页这种状态下干什么都卡。如果si和so一直为零但内存和cache也吃满了说明还没有真正触发交换接下来就要看谁的匿名页在推高水位。要揪出谁在吃内存一条命令足够ps aux --sort-%mem | head -20%mem列会按物理内存占用的百分比从高到低排序。需要注意的是这个百分比是“驻留内存RSS”的近似不是进程申请过的虚拟内存。你可能会发现Chromium系的进程一开就是几十个每个都占几百MB加起来非常可观。2.3 翻日志找OOM记录真相往往藏在journalctl里如果系统已经发生过卡死甚至自动杀掉进程先去日志里找证据journalctl -k | grep -i -E oom|out of memory|killed process这条命令会从内核日志里筛出所有和OOM相关的行。你会看到类似“Killed process 1234 (chrome) total-vm:...”的记录。日志里还会给出当时的内存状态摘要包括每个进程的占用排名。这是排查“上次到底发生了什么”的最佳途径。我有一个习惯在完成任何内存调优之前先把这个排查链路完整跑一遍记录free -h、vmstat的典型值再翻一遍OOM日志。没有这些基线数据你后面调了参数也很难判断是变好还是变坏。表格式总结如下排查步骤命令核心关注点查可用内存free -havailable是否长期偏低看实时换页vmstat 1si/so是否持续较大找大户进程ps aux --sort-%mem谁的总内存占用最高确认实际驻留smem比RSS更真实的物理内存占用翻OOM历史journalctl -kgrep -i oom第三步的smem可能很多人没装过它是基于/proc的统计工具能给出USS唯一驻留内存、PSS按共享比例折算的驻留内存和RSS三列。PSS比RSS更能反映真实物理内存占用因为它把共享库的占用按比例分摊了。抓“内存大户”时我一般先用smem -t -k -s pss。3. 最小改动先救急sysctl参数调优的正确姿势3.1swappiness内核多愿意用swap的“性格参数”我知道很多人一上来就问“swappiness设多少”我建议先理解它再动手。vm.swappiness的范围是0到100默认60表示内核在回收内存时倾向于从swap匿名页回收的权重。数值越低越不愿意用swap优先回收文件缓存数值越高越积极地把不常用的匿名页换到swap里给文件缓存留更多空间。桌面场景下大量内存是被文件缓存和匿名内存混合占用的。如果你用了较快的SSD设成10可以让系统尽量别把进程的内存页换出去卡顿感明显下降。如果你的内存特别小比如8GB以下完全不开swap也不行我更推荐配合第4章的zram一起使用让swap变成“压缩内存”而不是磁盘。修改方式有两种临时生效用sysctl -w vm.swappiness10永久生效写进/etc/sysctl.d/99-memory-tuning.confecho vm.swappiness10 | sudo tee /etc/sysctl.d/99-memory-tuning.conf sudo sysctl -p /etc/sysctl.d/99-memory-tuning.conf3.2vfs_cache_pressure回收目录和文件元数据缓存的力度这个参数控制内核回收目录项dentry和索引节点inode缓存的积极性。默认值100数值越高回收越激进。对于经常编译、频繁读写大量小文件的工作场景适当提高它可以把更多内存让给真正的程序使用。我个人的推荐是设成200但并不是越高越好。如果你经常访问同一批目录比如Web服务器反复读取无限多的静态文件太激进会导致元数据刚被回收又要重新读磁盘反而增加IO。普通桌面用户设成150-200体感都不错。3.3min_free_kbytes给系统兜底的内存水位线这个参数是很多教程容易忽略的。它设置了内核保留空闲内存的最低水位线避免在内存耗尽时连内核自己都拿不到可用页。计算公式建议为总内存的1%-2%。以32GB内存为例可以设min_free_kbytes524288512MB也就是总内存的1.5%左右。echo vm.min_free_kbytes524288 | sudo tee -a /etc/sysctl.d/99-memory-tuning.conf需要注意这个值宁可稍微高一点也不要太低。水位线太低时内存压力来得太快内核来不及做后台回收就只能走直接回收路径最容易触发卡顿和OOM。设太高也有副作用对内存极小的设备来说会浪费可用空间。一个32GB的机器设置后free -h里可以看到free部分会比之前多出几百MB这是正常现象。很多教程会把三个参数一次性塞给你我只想说别拿别人的参数直接套自己的机器。不同内存大小、不同磁盘类型、不同负载场景最优参数组合一定不一样。最小改动原则是先只调整swappiness和vfs_cache_pressure观察一周再决定要不要动min_free_kbytes。4. zram登场把交换从磁盘搬到内存压缩区卡顿的直接解法4.1 传统swap分区或swapfile为什么在桌面场景里救不了急传统做法是划分一个swap分区或者用fallocate做一个swapfile。这种方案的逻辑是“把不常用的内存页放到磁盘上”释放物理内存给当前活跃进程用。但它有两个硬伤第一磁盘IO速度远低于内存即使是最好的NVMe SSD随机读写也就几十万IOPS而内存是纳秒级的。一旦系统开始频繁换页swap读写就成了最大瓶颈。第二SSD有写入寿命限制频繁换页会快速消耗闪存寿命。我用一块老的128G SSD做过测试重度swap使用一个月就能看到SMART里的写入量飙升虽然不至于立刻损坏但看着心里发毛。所以对桌面用户来说swapfile不是不能用而是应该作为“最后的兜底”而不是日常换页的主力。4.2 zram是什么用CPU换速度把交换页压缩后留在内存里zram是在RAM里创建一个压缩块设备内核把要换出的页面先压缩再存进去。这样做的最大价值是swap操作不再依赖磁盘速度接近内存同时因为压缩率高通常能把换出的页面压到原来的1/3到1/2实际能用的“交换空间”比物理内存大不少。代价是需要消耗CPU进行压缩。现在主流的CPU都有硬件加速指令集配合lz4或zstd算法压缩和解压的开销完全可以接受。我用4核笔记本实测开启zram后编译大型项目CPU占用率上升不到3%但卡顿感几乎消失。Ubuntu启用zram有几种方式。我最推荐用zram-tools包简单直接sudo apt install zram-tools sudo dpkg-reconfigure zram-tools在配置界面里可以设置压缩算法为zstd设置PERCENT50。这表示zram大小是物理内存的50%。安装完成后用zramctl就能看到压缩设备的信息zramctl如果你习惯用systemd原生的方式也可以写/etc/systemd/zram-generator.conf[zram0] zram-size min(ram / 2, 8192) compression-algorithm zstdzram-size这个配置支持min()、max()这类表达式上面这个写法意思是“取物理内存一半和8GB两者中的较小值”适合内存比较大的机器。4.3 zram和zswap怎么选一张表讲清楚很多人会把zram和zswap搞混这俩名字像机制不同。zswap是一个在内核里的压缩缓存层它把要换出的页面先压缩然后存放在RAM里的动态池中如果池满了再把旧页面真正写入磁盘swap。可以说zswap是“给swap加了一层压缩缓存”。对比项zramzswap本质独立压缩块设备磁盘swap的压缩缓存层是否依赖磁盘swap不依赖依赖底层磁盘swap适用场景内存较小的桌面/嵌入式设备已有磁盘swap且不想改布局的场景推荐度桌面高中对大多数Ubuntu桌面用户来说zram更省心因为不用管磁盘swapfile的配置直接占用内存里的固定空间。如果内存只有4GBzram设成min(ram/2, 2048)比较合适设太大会让物理内存更紧张反而适得其反。开启zram之后记得检查一下free -h里的swap总量是不是变大了同时用zramctl看compressed和data的比值。如果data远大于compressed说明压缩算法工作良好如果两者接近说明你的内存页本身就很难压缩比如已经被压缩过的数据这时候再调整算法收益也不大。5. OOM杀掉重要程序从内核规矩讲到systemd-oomd5.1 内核OOM killer是怎么选“牺牲者”的别指望内核OOM killer聪明到帮你保IDE。内核通过给每个进程计算oom_score来选择牺牲者基础分和进程内存占用正相关同时可以通过oom_score_adj调整优先级。分数最高的进程会被杀而oom_score_adj可以在/proc/pid/oom_score_adj里手动设置取值从-1000到1000-1000表示这个进程永远不会被OOM killer选中。问题就是浏览器、IDE、桌面环境这些大进程往往内存占用最高OOM killer杀掉它们对释放内存最“见效”但对你来说就是灾难。我曾经遇到过一个编辑器进程被OOM杀掉辛辛苦苦写了一下午的笔记全部丢失。5.2 用systemd保护关键服务别让老大哥乱点名如果你希望某个关键服务永远不被OOM杀掉可以写systemd服务单元[Service] OOMScoreAdjust-500或者对普通进程临时用echo -500 | sudo tee /proc/pid/oom_score_adj负值代表降低被选中的概率。不过要小心不能给太多进程都设负值否则OOM killer只能找其他进程下手等于强迫它去杀你没设保护的程序。5.3 systemd-oomdUbuntu 22.04自带的用户态内存守护从systemd 247开始systemd增加了oomdUbuntu 22.04及后续版本默认启用systemd-oomd.service。它的好处是比内核OOM killer更早介入通过cgroup级别的内存压力和swap使用量判断优先杀掉“大而不重要”的cgroup里的进程而不是整个系统找最吃内存的进程杀掉。检查它是否在运行systemctl status systemd-oomd它的配置文件在/etc/systemd/oomd.conf一个常见配置长这样[OOM] SwapUsedLimit90% DefaultMemoryPressureLimit60%SwapUsedLimit90%表示当swap使用率达到90%时oomd开始kill占用最多的cgroup里的进程DefaultMemoryPressureLimit60%表示当cgroup内存压力累计值超过60%时oomd也会介入。这样你可以给浏览器这类应用所在的cgroup单独配置更高的阈值而不是一刀切。需要提醒的是systemd-oomd只对使用cgroup v2的slice生效而且它主要关注系统的整体“健康度”而不是具体恢复某个程序。如果你需要更针对性的保护配合OOMScoreAdjust一起用更稳妥。5.4 earlyoom作为备选方案如果你的系统版本较老或者你希望OOM处理更“主动”可以尝试earlyoom。它是一个独立守护进程常驻后台监控可用内存和swap当内存降到预设阈值时会优先杀掉得分最高的进程并且允许通过配置文件忽略特定进程名比如--ignore chromium|code。sudo apt install earlyoom sudo systemctl enable --now earlyoomearlyoom的优势是响应比内核OOM killer快得多避免系统进入半死状态。劣势是它杀进程的逻辑也需要自己调优先保护的进程名单要维护好。总的来说我建议优先用systemd-oomd因为它和系统组件配合更紧密老版本或者特别网络环境受限的机器再考虑earlyoom。6. 调完怎么算成功压测方法与长期监控6.1 用stress-ng主动制造内存压力验证优化效果调完参数之后最怕的是“感觉好像不卡了”这种无法量化的结论。我建议你主动压测。安装stress-ngsudo apt install stress-ng然后用下面这条命令制造约4GB的内存压力持续120秒stress-ng --vm 4 --vm-bytes 2G --timeout 120s在压测期间另开一个终端同时观察vmstat 1和free -h重点看si/so是不是被抑制了available是不是还能维持在一个合理区间系统是否还能正常切换窗口。如果你配置了zram压测时可以在第三个终端持续跑zramctl看压缩设备有没有在被正常使用。我实测过的组合配置swappiness10 zram 32GB内存在4GB压力下几乎稳定在“有少量swap换入但不再卡死”的状态而同一台机器没调优前2GB压力就能让UI卡得没法看。6.2 长期监控让数据告诉你是否需要再调一次压测不代表长期效果。我建议你至少让系统运行一周期间定期记录free -h里的available最低值journalctl -k | grep -i oom是否出现新的OOM记录systemctl status systemd-oomd有没有频繁触发kill如果available在高峰期仍然长期低于1GB说明要么内存还是不够要么缓存回收策略仍然偏保守可以考虑增加物理内存而不是继续压榨参数。反过来如果OOM日志彻底消失卡顿感也消失那这套配置基本可以固定下来。6.3 针对不同机器的一张经验配置表场景内存大小swappinessvfs_cache_pressure交换方案systemd-oomd老笔记本轻度办公4GB10150zram 2GB 磁盘swapfile 2GB启用日常开发机16GB10150zram 4GB启用高性能工作站32GB5-10200不配swap或配zRAM 8GB兜底启用服务器web服务8GB-32GB30100swapfile 4GB或按需根据业务选服务器场景我特意把swappiness设高是因为服务端通常更看重缓存命中率而不是交互响应速度。这也是为什么我一直强调不能照搬——你的笔记本优化配置直接扔到服务器上效果可能完全不同。6.4 我踩过的那些坑提前帮你避开最后分享几个实际经验。第一个坑是盲目设很大的zram。我之前在一台16GB的机器上把zram设成了12GB结果物理内存被压缩设备占掉了一大块普通负载看起来可用内存也不多反而更卡。现在的建议是zram不要超过物理内存的50%除非你确定自己的负载有很强的可压缩性。第二个坑是给所有程序都设OOMScoreAdjust负值。这样做等于让OOM killer无处下刀最后它只能去杀最关键的中间进程。保护的范围一定要小控制在编辑器、浏览器这类不可替代的交互进程就行。第三个坑是只调参不确认效果。参数调完之后至少要经过一次真实的高负载场景验证压测、编译、开几十个标签页而不是感觉“桌面流畅了点就叫优化完成”。判断的标准永远是数据available是否撑得住、si/so是否明显下降、OOM记录是否消失。这套流程走下来Ubuntu的内存管理基本就能做到“平时安静、压力来时不乱、极限时保命”。每个参数都不是越多越好。动手改之前先把第2章的排查链路完整跑一遍拿着数据去对照第6章的配置表做选择效果会远超照着网上参数盲调。如果你调完一段时间后有了自己的实测数据也欢迎回来交流你是在什么样的机器上改的、改了什么、体感如何。

读完文章,也想定制专属网站?

尧图设计师 24 小时内与您沟通定制方案

免费获取报价 →
↑