Ubuntu 22.04 的 cgroup v2 上把某个服务的 memory.max 从 2G 改成 1G,set-property 执行成功,进程当场被杀,dmesg 里是 Memory cgroup out of memory,应用日志没有任何异常。

一开始怀疑是「进程有大量匿名页回收不动,内核只能挑一个进程杀掉」,查了一圈,方向不对。

排查方向其实有限,先把可能性排一排。memory.max 是硬上限,改到低于当前匿名页用量会立刻触发 cgroup OOM。少数情况下是memory.current 里还包含 page cache,真正可回收的量比看上去少。

还有一种情况,MemorySwapMax 是 0 时没有缓冲,回收不动就直接 OOM。

动手时先看这个 cgroup 的内存构成

cat /sys/fs/cgroup/system.slice/app.service/memory.current && grep -E '^(anon|file|slab) ' /sys/fs/cgroup/system.slice/app.service/memory.stat

手工回收页缓存再调限额

echo 900M > /sys/fs/cgroup/system.slice/app.service/memory.reclaim

再往下用 memory.high 做过渡而不是硬砍

systemctl set-property app.service MemoryHigh=1G MemoryMax=1500M

剩下的就是看事件计数确认不再有新杀

cat /sys/fs/cgroup/system.slice/app.service/memory.events

我习惯把每一步的执行时间和结果记在一边,后面复盘省事。

别只看报错消失,验证要多做一步。memory.events 的 oom_kill 不再增长,memory.current 峰值稳定在 1.4G 以下,服务连续运行不掉。

补一句。改 memory.max 前先看 memory.peak,低于当前用量就是立刻见血;memory.high 会限速回收,比硬砍温和得多。改动前把原配置备份一份,出问题能马上回滚,这比任何技巧都实用。

作者 9823189