PostgreSQL 和 OOM killer:我们为何使用严格内存超额分配
Linux 超额分配模式 & PostgreSQL
- 若干评论者强调,严格超额分配(
vm.overcommit_memory=2)可能会破坏fork()和应用重启,尤其是在超额分配比例已经调优过的情况下。 - 建议:先在 QA/性能环境中严格测试,进行压测,并在通过部署脚本逐步引入后,再把它写进
sysctl。 - 有些人更偏好启发式模式(
0),配合很低的overcommit_ratio,并大量使用oom_score_adj(例如关键服务设为 -1000),再加上内核保留内存调优。 - 就 PostgreSQL 而言,严格超额分配很有吸引力,因为它能优雅地处理
ENOMEM,并回滚事务,而不是崩溃。
共享主机:Go / 托管语言 vs Postgres
- 现实中的问题:Go 后端和 Postgres 跑在同一台主机上。
- 启发式超额分配导致 Postgres 分配失败;严格超额分配则因为 Go 的大量虚拟内存保留让整个系统变得不稳定。
- 变通办法:根据经验调优
overcommit_ratio,使用 GOMEMLIMIT 限制 Go 堆,或者把数据库和应用隔离到不同节点,或通过容器/cgroups 隔离。
OOM killer vs 分配失败
- 对于是否关闭超额分配,争议很大。
- 一些用户禁用超额分配,更愿意接受短暂卡死,然后手动关闭应用,而不是让内核杀掉“随机的”或关键进程。
- 另一些人认为这只是把 OOM 杀进程换成了
ENOMEM崩溃,因为大多数桌面软件都不会处理分配失败,并且可能破坏状态。 - 内核 OOM killer 在桌面上的行为普遍被批评为缓慢、不可预测且对用户不友好。
Windows/macOS 和 swap / 压缩
- 多条评论将 Linux 与 Windows 对比:Windows 跟踪提交量(commit charge),从不进行超额分配,而且通常能更平稳地处理低内存情况。
- 有人说 Windows 实际上没有“OOM killer”,而是拒绝不合理的分配;也有人指出它仍然可能杀掉问题应用,或提示关闭有问题的应用。
- 关于禁用 Windows 页面文件的争论:有人这样做是为了“禁用超额分配”,也有人称这几乎总是个坏主意,并强调页面文件是安全保障。
- 在 Linux 上,评论者主张使用 swap、zram/zswap、MGLRU 和用户态 OOM 守护进程作为更合理的默认选择,尤其相较于超大规模云厂商式的“无 swap”配置。
更广泛的设计 / 语言角度
- 有人认为桌面端的严格超额分配是个地雷,因为普遍忽视
malloc错误处理。 - 也有人强调,健壮的系统(尤其是数据库)应该实现自己的内存记账和 OOM 策略。
- 一个旁支讨论建议,Rust 更丰富的类型(枚举/Result)本可以避免文章中讨论的那个特定 C 整数/布尔 bug。