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。